Aktueller Stand
This commit is contained in:
3
backend/node_modules/fastify/.borp.yaml
generated
vendored
Normal file
3
backend/node_modules/fastify/.borp.yaml
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
files:
|
||||
- 'test/**/*.test.js'
|
||||
- 'test/**/*.test.mjs'
|
||||
8
backend/node_modules/fastify/.c8rc.json
generated
vendored
8
backend/node_modules/fastify/.c8rc.json
generated
vendored
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"exclude": [
|
||||
"lib/configValidator.js",
|
||||
"lib/error-serializer.js",
|
||||
"build/build-error-serializer.js",
|
||||
"test/*"
|
||||
]
|
||||
}
|
||||
4
backend/node_modules/fastify/.eslintrc
generated
vendored
4
backend/node_modules/fastify/.eslintrc
generated
vendored
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"root": true,
|
||||
"extends": "standard"
|
||||
}
|
||||
2
backend/node_modules/fastify/.markdownlint-cli2.yaml
generated
vendored
2
backend/node_modules/fastify/.markdownlint-cli2.yaml
generated
vendored
@@ -7,7 +7,7 @@ config:
|
||||
MD013:
|
||||
line_length: 80
|
||||
code_block_line_length: 120
|
||||
headers: false
|
||||
headings: false
|
||||
tables: false
|
||||
strict: false
|
||||
stern: false
|
||||
|
||||
11
backend/node_modules/fastify/.taprc
generated
vendored
11
backend/node_modules/fastify/.taprc
generated
vendored
@@ -1,11 +0,0 @@
|
||||
ts: false
|
||||
jsx: false
|
||||
flow: false
|
||||
# the coverage is performed by c8
|
||||
check-coverage: false
|
||||
coverage: false
|
||||
node-arg: --allow-natives-syntax
|
||||
|
||||
files:
|
||||
- 'test/**/*.test.js'
|
||||
- 'test/**/*.test.mjs'
|
||||
2
backend/node_modules/fastify/LICENSE
generated
vendored
2
backend/node_modules/fastify/LICENSE
generated
vendored
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016-2024 The Fastify Team
|
||||
Copyright (c) 2016-present The Fastify Team
|
||||
|
||||
The Fastify team members are listed at https://github.com/fastify/fastify#team
|
||||
and in the README file.
|
||||
|
||||
14
backend/node_modules/fastify/PROJECT_CHARTER.md
generated
vendored
14
backend/node_modules/fastify/PROJECT_CHARTER.md
generated
vendored
@@ -1,6 +1,6 @@
|
||||
# Fastify Charter
|
||||
|
||||
The Fastify project aims to build a fast and low overhead web framework for
|
||||
The Fastify project aims to build a fast and low-overhead web framework for
|
||||
Node.js.
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ experience with the least overhead and a plugin architecture.
|
||||
### 1.1: In-scope
|
||||
|
||||
+ Develop a web framework for Node.js with a focus on developer experience,
|
||||
performance and extensibility.
|
||||
performance, and extensibility.
|
||||
+ Plugin Architecture
|
||||
+ Support web protocols
|
||||
+ Official plugins for common user requirements
|
||||
@@ -43,7 +43,7 @@ experience with the least overhead and a plugin architecture.
|
||||
|
||||
+ Support versions of Node.js at EOL (end of life) stage
|
||||
+ Support serverless architecture
|
||||
+ Contributions that violates the [Code of Conduct](CODE_OF_CONDUCT.md)
|
||||
+ Contributions that violate the [Code of Conduct](CODE_OF_CONDUCT.md)
|
||||
|
||||
|
||||
## Section 2: Relationship with OpenJS Foundation CPC.
|
||||
@@ -58,10 +58,10 @@ the Board of Directors (the "Board").
|
||||
This Fastify Charter reflects a carefully constructed balanced role for the
|
||||
Collaborators and the CPC in the governance of the OpenJS Foundation. The
|
||||
charter amendment process is for the Fastify Collaborators to propose change
|
||||
using simple majority of the full Fastify Organization, the proposed changes
|
||||
using a majority of the full Fastify Organization, the proposed changes
|
||||
being subject to review and approval by the CPC. The CPC may additionally make
|
||||
amendments to the Collaborators charter at any time, though the CPC will not
|
||||
interfere with day-to-day discussions, votes or meetings of the Fastify
|
||||
interfere with day-to-day discussions, votes, or meetings of the Fastify
|
||||
Organization.
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ Section Intentionally Left Blank
|
||||
Fastify's features can be discussed in GitHub issues and/or projects. Consensus
|
||||
on a discussion is reached when there is no objection by any collaborators.
|
||||
|
||||
Whenever there is not consensus, Lead Maintainers will have final say on the
|
||||
When there is no consensus, Lead Maintainers will have the final say on the
|
||||
topic.
|
||||
|
||||
**Voting, and/or Elections**
|
||||
@@ -112,7 +112,7 @@ Section Intentionally Left Blank
|
||||
Foundation Board.
|
||||
|
||||
+ *Collaborators*: contribute code and other artifacts, have the right to commit
|
||||
to the code base and release plugins projects. Collaborators follow the
|
||||
to the code base, and release plugin projects. Collaborators follow the
|
||||
[CONTRIBUTING](CONTRIBUTING.md) guidelines to manage the project. A
|
||||
Collaborator could be encumbered by other Fastify Collaborators and never by
|
||||
the CPC or OpenJS Foundation Board.
|
||||
|
||||
225
backend/node_modules/fastify/README.md
generated
vendored
225
backend/node_modules/fastify/README.md
generated
vendored
@@ -9,12 +9,12 @@
|
||||
|
||||
<div align="center">
|
||||
|
||||
[](https://github.com/fastify/fastify/actions/workflows/ci.yml)
|
||||
[](https://github.com/fastify/fastify/actions/workflows/ci.yml)
|
||||
[](https://github.com/fastify/fastify/actions/workflows/package-manager-ci.yml)
|
||||
CI](https://github.com/fastify/fastify/actions/workflows/package-manager-ci.yml/badge.svg?branch=main)](https://github.com/fastify/fastify/actions/workflows/package-manager-ci.yml)
|
||||
[](https://github.com/fastify/fastify/actions/workflows/website.yml)
|
||||
[](https://standardjs.com/)
|
||||
site](https://github.com/fastify/fastify/actions/workflows/website.yml/badge.svg?branch=main)](https://github.com/fastify/fastify/actions/workflows/website.yml)
|
||||
[](https://github.com/neostandard/neostandard)
|
||||
[](https://bestpractices.coreinfrastructure.org/projects/7585)
|
||||
|
||||
</div>
|
||||
@@ -29,16 +29,16 @@ downloads](https://img.shields.io/npm/dm/fastify.svg?style=flat)](https://www.np
|
||||
Disclosure](https://img.shields.io/badge/Security-Responsible%20Disclosure-yellow.svg)](https://github.com/fastify/fastify/blob/main/SECURITY.md)
|
||||
[](https://discord.gg/fastify)
|
||||
[](https://gitpod.io/#https://github.com/fastify/fastify)
|
||||

|
||||
[](https://github.com/sponsors/fastify#sponsors)
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
An efficient server implies a lower cost of the infrastructure, a better
|
||||
responsiveness under load and happy users. How can you efficiently handle the
|
||||
An efficient server implies a lower cost of the infrastructure, better
|
||||
responsiveness under load, and happy users. How can you efficiently handle the
|
||||
resources of your server, knowing that you are serving the highest number of
|
||||
requests as possible, without sacrificing security validations and handy
|
||||
requests possible, without sacrificing security validations and handy
|
||||
development?
|
||||
|
||||
Enter Fastify. Fastify is a web framework highly focused on providing the best
|
||||
@@ -46,17 +46,14 @@ developer experience with the least overhead and a powerful plugin architecture.
|
||||
It is inspired by Hapi and Express and as far as we know, it is one of the
|
||||
fastest web frameworks in town.
|
||||
|
||||
The `main` branch refers to the Fastify `v4` release. Check out the
|
||||
[`v3.x` branch](https://github.com/fastify/fastify/tree/3.x) for `v3`.
|
||||
|
||||
|
||||
The `main` branch refers to the Fastify `v5` release.
|
||||
Check out the [`4.x` branch](https://github.com/fastify/fastify/tree/4.x) for `v4`.
|
||||
|
||||
### Table of Contents
|
||||
|
||||
- [Quick start](#quick-start)
|
||||
- [Install](#install)
|
||||
- [Example](#example)
|
||||
- [Fastify v1.x and v2.x](#fastify-v1x-and-v2x)
|
||||
- [Core features](#core-features)
|
||||
- [Benchmarks](#benchmarks)
|
||||
- [Documentation](#documentation)
|
||||
@@ -109,14 +106,9 @@ generate functionality of [Fastify CLI](https://github.com/fastify/fastify-cli).
|
||||
|
||||
To install Fastify in an existing project as a dependency:
|
||||
|
||||
Install with npm:
|
||||
```sh
|
||||
npm i fastify
|
||||
```
|
||||
Install with yarn:
|
||||
```sh
|
||||
yarn add fastify
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
@@ -146,7 +138,7 @@ fastify.listen({ port: 3000 }, (err, address) => {
|
||||
})
|
||||
```
|
||||
|
||||
with async-await:
|
||||
With async-await:
|
||||
|
||||
```js
|
||||
// ESM
|
||||
@@ -173,13 +165,14 @@ fastify.listen({ port: 3000 }, (err, address) => {
|
||||
|
||||
Do you want to know more? Head to the <a
|
||||
href="./docs/Guides/Getting-Started.md"><code><b>Getting Started</b></code></a>.
|
||||
If you learn best by reading code, explore the official [demo](https://github.com/fastify/demo).
|
||||
|
||||
> ## Note
|
||||
> `.listen` binds to the local host, `localhost`, interface by default
|
||||
> (`127.0.0.1` or `::1`, depending on the operating system configuration). If
|
||||
> you are running Fastify in a container (Docker,
|
||||
> [GCP](https://cloud.google.com/), etc.), you may need to bind to `0.0.0.0`. Be
|
||||
> careful when deciding to listen on all interfaces; it comes with inherent
|
||||
> careful when listening on all interfaces; it comes with inherent
|
||||
> [security
|
||||
> risks](https://web.archive.org/web/20170711105010/https://snyk.io/blog/mongodb-hack-and-secure-defaults/).
|
||||
> See [the documentation](./docs/Reference/Server.md#listen) for more
|
||||
@@ -190,16 +183,16 @@ href="./docs/Guides/Getting-Started.md"><code><b>Getting Started</b></code></a>.
|
||||
- **Highly performant:** as far as we know, Fastify is one of the fastest web
|
||||
frameworks in town, depending on the code complexity we can serve up to 76+
|
||||
thousand requests per second.
|
||||
- **Extensible:** Fastify is fully extensible via its hooks, plugins and
|
||||
- **Extensible:** Fastify is fully extensible via its hooks, plugins, and
|
||||
decorators.
|
||||
- **Schema based:** even if it is not mandatory we recommend to use [JSON
|
||||
- **Schema-based:** even if it is not mandatory we recommend using [JSON
|
||||
Schema](https://json-schema.org/) to validate your routes and serialize your
|
||||
outputs, internally Fastify compiles the schema in a highly performant
|
||||
outputs. Internally Fastify compiles the schema in a highly performant
|
||||
function.
|
||||
- **Logging:** logs are extremely important but are costly; we chose the best
|
||||
logger to almost remove this cost, [Pino](https://github.com/pinojs/pino)!
|
||||
- **Developer friendly:** the framework is built to be very expressive and help
|
||||
the developer in their daily use, without sacrificing performance and
|
||||
developers in their daily use without sacrificing performance and
|
||||
security.
|
||||
|
||||
### Benchmarks
|
||||
@@ -219,10 +212,10 @@ second average
|
||||
| - | | | |
|
||||
| `http.Server` | 16.14.2 | ✗ | 74,513 |
|
||||
|
||||
Benchmarks taken using https://github.com/fastify/benchmarks. This is a
|
||||
synthetic, "hello world" benchmark that aims to evaluate the framework overhead.
|
||||
These benchmarks taken using https://github.com/fastify/benchmarks. This is a
|
||||
synthetic "hello world" benchmark that aims to evaluate the framework overhead.
|
||||
The overhead that each framework has on your application depends on your
|
||||
application, you should __always__ benchmark if performance matters to you.
|
||||
application. You should __always__ benchmark if performance matters to you.
|
||||
|
||||
## Documentation
|
||||
* [__`Getting Started`__](./docs/Guides/Getting-Started.md)
|
||||
@@ -252,13 +245,11 @@ application, you should __always__ benchmark if performance matters to you.
|
||||
* [__`Serverless`__](./docs/Guides/Serverless.md)
|
||||
* [__`Recommendations`__](./docs/Guides/Recommendations.md)
|
||||
|
||||
中文文档[地址](https://github.com/fastify/docs-chinese/blob/HEAD/README.md)
|
||||
|
||||
## Ecosystem
|
||||
|
||||
- [Core](./docs/Guides/Ecosystem.md#core) - Core plugins maintained by the
|
||||
_Fastify_ [team](#team).
|
||||
- [Community](./docs/Guides/Ecosystem.md#community) - Community supported
|
||||
- [Community](./docs/Guides/Ecosystem.md#community) - Community-supported
|
||||
plugins.
|
||||
- [Live Examples](https://github.com/fastify/example) - Multirepo with a broad
|
||||
set of real working examples.
|
||||
@@ -269,9 +260,17 @@ application, you should __always__ benchmark if performance matters to you.
|
||||
Please visit [Fastify help](https://github.com/fastify/help) to view prior
|
||||
support issues and to ask new support questions.
|
||||
|
||||
Version 3 of Fastify and lower are EOL and will not receive any security or bug
|
||||
fixes.
|
||||
|
||||
Fastify's partner, HeroDevs, provides commercial security fixes for all
|
||||
unsupported versions at [https://herodevs.com/support/fastify-nes][hd-link].
|
||||
Fastify's supported version matrix is available in the
|
||||
[Long Term Support][lts-link] documentation.
|
||||
|
||||
## Contributing
|
||||
|
||||
Whether reporting bugs, discussing improvements and new ideas or writing code,
|
||||
Whether reporting bugs, discussing improvements and new ideas, or writing code,
|
||||
we welcome contributions from anyone and everyone. Please read the [CONTRIBUTING](./CONTRIBUTING.md)
|
||||
guidelines before submitting pull requests.
|
||||
|
||||
@@ -282,98 +281,103 @@ listed in alphabetical order.
|
||||
|
||||
**Lead Maintainers:**
|
||||
* [__Matteo Collina__](https://github.com/mcollina),
|
||||
<https://twitter.com/matteocollina>, <https://www.npmjs.com/~matteo.collina>
|
||||
<https://x.com/matteocollina>, <https://www.npmjs.com/~matteo.collina>
|
||||
* [__Tomas Della Vedova__](https://github.com/delvedor),
|
||||
<https://twitter.com/delvedor>, <https://www.npmjs.com/~delvedor>
|
||||
<https://x.com/delvedor>, <https://www.npmjs.com/~delvedor>
|
||||
* [__KaKa Ng__](https://github.com/climba03003),
|
||||
<https://www.npmjs.com/~climba03003>
|
||||
* [__Manuel Spigolon__](https://github.com/eomm),
|
||||
<https://twitter.com/manueomm>, <https://www.npmjs.com/~eomm>
|
||||
<https://x.com/manueomm>, <https://www.npmjs.com/~eomm>
|
||||
* [__James Sumners__](https://github.com/jsumners),
|
||||
<https://twitter.com/jsumners79>, <https://www.npmjs.com/~jsumners>
|
||||
<https://x.com/jsumners79>, <https://www.npmjs.com/~jsumners>
|
||||
|
||||
### Fastify Core team
|
||||
* [__Tommaso Allevi__](https://github.com/allevo),
|
||||
<https://twitter.com/allevitommaso>, <https://www.npmjs.com/~allevo>
|
||||
* [__Harry Brundage__](https://github.com/airhorns/),
|
||||
<https://twitter.com/harrybrundage>, <https://www.npmjs.com/~airhorns>
|
||||
* [__David Mark Clements__](https://github.com/davidmarkclements),
|
||||
<https://twitter.com/davidmarkclem>,
|
||||
<https://www.npmjs.com/~davidmarkclements>
|
||||
* [__Matteo Collina__](https://github.com/mcollina),
|
||||
<https://twitter.com/matteocollina>, <https://www.npmjs.com/~matteo.collina>
|
||||
* [__Tomas Della Vedova__](https://github.com/delvedor),
|
||||
<https://twitter.com/delvedor>, <https://www.npmjs.com/~delvedor>
|
||||
* [__Dustin Deus__](https://github.com/StarpTech),
|
||||
<https://twitter.com/dustindeus>, <https://www.npmjs.com/~starptech>
|
||||
* [__Ayoub El Khattabi__](https://github.com/AyoubElk),
|
||||
<https://twitter.com/ayoubelkh>, <https://www.npmjs.com/~ayoubelk>
|
||||
* [__Denis Fäcke__](https://github.com/SerayaEryn),
|
||||
<https://twitter.com/serayaeryn>, <https://www.npmjs.com/~serayaeryn>
|
||||
* [__Carlos Fuentes__](https://github.com/metcoder95),
|
||||
<https://twitter.com/metcoder95>, <https://www.npmjs.com/~metcoder95>
|
||||
* [__Rafael Gonzaga__](https://github.com/rafaelgss),
|
||||
<https://twitter.com/_rafaelgss>, <https://www.npmjs.com/~rafaelgss>
|
||||
* [__Vincent Le Goff__](https://github.com/zekth)
|
||||
* [__Luciano Mammino__](https://github.com/lmammino),
|
||||
<https://twitter.com/loige>, <https://www.npmjs.com/~lmammino>
|
||||
* [__Luis Orbaiceta__](https://github.com/luisorbaiceta),
|
||||
<https://twitter.com/luisorbai>, <https://www.npmjs.com/~luisorbaiceta>
|
||||
* [__Maksim Sinik__](https://github.com/fox1t),
|
||||
<https://twitter.com/maksimsinik>, <https://www.npmjs.com/~fox1t>
|
||||
* [__Manuel Spigolon__](https://github.com/eomm),
|
||||
<https://twitter.com/manueomm>, <https://www.npmjs.com/~eomm>
|
||||
* [__James Sumners__](https://github.com/jsumners),
|
||||
<https://twitter.com/jsumners79>, <https://www.npmjs.com/~jsumners>
|
||||
* [__Aras Abbasi__](https://github.com/uzlopak),
|
||||
<https://www.npmjs.com/~uzlopak>
|
||||
* [__Harry Brundage__](https://github.com/airhorns/),
|
||||
<https://x.com/harrybrundage>, <https://www.npmjs.com/~airhorns>
|
||||
* [__Matteo Collina__](https://github.com/mcollina),
|
||||
<https://x.com/matteocollina>, <https://www.npmjs.com/~matteo.collina>
|
||||
* [__Gürgün Dayıoğlu__](https://github.com/gurgunday),
|
||||
<https://www.npmjs.com/~gurgunday>
|
||||
* [__Tomas Della Vedova__](https://github.com/delvedor),
|
||||
<https://x.com/delvedor>, <https://www.npmjs.com/~delvedor>
|
||||
* [__Carlos Fuentes__](https://github.com/metcoder95),
|
||||
<https://x.com/metcoder95>, <https://www.npmjs.com/~metcoder95>
|
||||
* [__Vincent Le Goff__](https://github.com/zekth)
|
||||
* [__Luciano Mammino__](https://github.com/lmammino),
|
||||
<https://x.com/loige>, <https://www.npmjs.com/~lmammino>
|
||||
* [__Jean Michelet__](https://github.com/jean-michelet),
|
||||
<https://www.npmjs.com/~jean-michelet>
|
||||
* [__KaKa Ng__](https://github.com/climba03003),
|
||||
<https://www.npmjs.com/~climba03003>
|
||||
* [__Luis Orbaiceta__](https://github.com/luisorbaiceta),
|
||||
<https://x.com/luisorbai>, <https://www.npmjs.com/~luisorbaiceta>
|
||||
* [__Maksim Sinik__](https://github.com/fox1t),
|
||||
<https://x.com/maksimsinik>, <https://www.npmjs.com/~fox1t>
|
||||
* [__Manuel Spigolon__](https://github.com/eomm),
|
||||
<https://x.com/manueomm>, <https://www.npmjs.com/~eomm>
|
||||
* [__James Sumners__](https://github.com/jsumners),
|
||||
<https://x.com/jsumners79>, <https://www.npmjs.com/~jsumners>
|
||||
|
||||
### Fastify Plugins team
|
||||
* [__Matteo Collina__](https://github.com/mcollina),
|
||||
<https://twitter.com/matteocollina>, <https://www.npmjs.com/~matteo.collina>
|
||||
* [__Harry Brundage__](https://github.com/airhorns/),
|
||||
<https://twitter.com/harrybrundage>, <https://www.npmjs.com/~airhorns>
|
||||
* [__Tomas Della Vedova__](https://github.com/delvedor),
|
||||
<https://twitter.com/delvedor>, <https://www.npmjs.com/~delvedor>
|
||||
* [__Ayoub El Khattabi__](https://github.com/AyoubElk),
|
||||
<https://twitter.com/ayoubelkh>, <https://www.npmjs.com/~ayoubelk>
|
||||
* [__Carlos Fuentes__](https://github.com/metcoder95),
|
||||
<https://twitter.com/metcoder95>, <https://www.npmjs.com/~metcoder95>
|
||||
* [__Vincent Le Goff__](https://github.com/zekth)
|
||||
* [__Salman Mitha__](https://github.com/salmanm),
|
||||
<https://www.npmjs.com/~salmanm>
|
||||
* [__Maksim Sinik__](https://github.com/fox1t),
|
||||
<https://twitter.com/maksimsinik>, <https://www.npmjs.com/~fox1t>
|
||||
* [__Frazer Smith__](https://github.com/Fdawgs), <https://www.npmjs.com/~fdawgs>
|
||||
* [__Manuel Spigolon__](https://github.com/eomm),
|
||||
<https://twitter.com/manueomm>, <https://www.npmjs.com/~eomm>
|
||||
<https://x.com/harrybrundage>, <https://www.npmjs.com/~airhorns>
|
||||
* [__Simone Busoli__](https://github.com/simoneb),
|
||||
<https://twitter.com/simonebu>, <https://www.npmjs.com/~simoneb>
|
||||
<https://x.com/simonebu>, <https://www.npmjs.com/~simoneb>
|
||||
* [__Dan Castillo__](https://github.com/dancastillo),
|
||||
<https://www.npmjs.com/~dancastillo>
|
||||
* [__Matteo Collina__](https://github.com/mcollina),
|
||||
<https://x.com/matteocollina>, <https://www.npmjs.com/~matteo.collina>
|
||||
* [__Gürgün Dayıoğlu__](https://github.com/gurgunday),
|
||||
<https://www.npmjs.com/~gurgunday>
|
||||
* [__Tomas Della Vedova__](https://github.com/delvedor),
|
||||
<https://x.com/delvedor>, <https://www.npmjs.com/~delvedor>
|
||||
* [__Carlos Fuentes__](https://github.com/metcoder95),
|
||||
<https://x.com/metcoder95>, <https://www.npmjs.com/~metcoder95>
|
||||
* [__Vincent Le Goff__](https://github.com/zekth)
|
||||
* [__Jean Michelet__](https://github.com/jean-michelet),
|
||||
<https://www.npmjs.com/~jean-michelet>
|
||||
* [__KaKa Ng__](https://github.com/climba03003),
|
||||
<https://www.npmjs.com/~climba03003>
|
||||
* [__Maksim Sinik__](https://github.com/fox1t),
|
||||
<https://x.com/maksimsinik>, <https://www.npmjs.com/~fox1t>
|
||||
* [__Frazer Smith__](https://github.com/Fdawgs), <https://www.npmjs.com/~fdawgs>
|
||||
* [__Manuel Spigolon__](https://github.com/eomm),
|
||||
<https://x.com/manueomm>, <https://www.npmjs.com/~eomm>
|
||||
|
||||
### Great Contributors
|
||||
Great contributors on a specific area in the Fastify ecosystem will be invited
|
||||
to join this group by Lead Maintainers.
|
||||
### Emeritus Contributors
|
||||
Great contributors to a specific area of the Fastify ecosystem will be invited
|
||||
to join this group by Lead Maintainers when they decide to step down from the
|
||||
active contributor's group.
|
||||
|
||||
* [__dalisoft__](https://github.com/dalisoft), <https://twitter.com/dalisoft>,
|
||||
<https://www.npmjs.com/~dalisoft>
|
||||
* [__Luciano Mammino__](https://github.com/lmammino),
|
||||
<https://twitter.com/loige>, <https://www.npmjs.com/~lmammino>
|
||||
* [__Evan Shortiss__](https://github.com/evanshortiss),
|
||||
<https://twitter.com/evanshortiss>, <https://www.npmjs.com/~evanshortiss>
|
||||
|
||||
**Past Collaborators**
|
||||
* [__Çağatay Çalı__](https://github.com/cagataycali),
|
||||
<https://twitter.com/cagataycali>, <https://www.npmjs.com/~cagataycali>
|
||||
* [__Trivikram Kamat__](https://github.com/trivikr),
|
||||
<https://twitter.com/trivikram>, <https://www.npmjs.com/~trivikr>
|
||||
* [__Cemre Mengu__](https://github.com/cemremengu),
|
||||
<https://twitter.com/cemremengu>, <https://www.npmjs.com/~cemremengu>
|
||||
* [__Nathan Woltman__](https://github.com/nwoltman),
|
||||
<https://twitter.com/NathanWoltman>, <https://www.npmjs.com/~nwoltman>
|
||||
* [__Tommaso Allevi__](https://github.com/allevo),
|
||||
<https://x.com/allevitommaso>, <https://www.npmjs.com/~allevo>
|
||||
* [__Ethan Arrowood__](https://github.com/Ethan-Arrowood/),
|
||||
<https://twitter.com/arrowoodtech>, <https://www.npmjs.com/~ethan_arrowood>
|
||||
<https://x.com/arrowoodtech>, <https://www.npmjs.com/~ethan_arrowood>
|
||||
* [__Çağatay Çalı__](https://github.com/cagataycali),
|
||||
<https://x.com/cagataycali>, <https://www.npmjs.com/~cagataycali>
|
||||
* [__David Mark Clements__](https://github.com/davidmarkclements),
|
||||
<https://x.com/davidmarkclem>,
|
||||
<https://www.npmjs.com/~davidmarkclements>
|
||||
* [__dalisoft__](https://github.com/dalisoft), <https://x.com/dalisoft>,
|
||||
<https://www.npmjs.com/~dalisoft>
|
||||
* [__Dustin Deus__](https://github.com/StarpTech),
|
||||
<https://x.com/dustindeus>, <https://www.npmjs.com/~starptech>
|
||||
* [__Denis Fäcke__](https://github.com/SerayaEryn),
|
||||
<https://x.com/serayaeryn>, <https://www.npmjs.com/~serayaeryn>
|
||||
* [__Rafael Gonzaga__](https://github.com/rafaelgss),
|
||||
<https://x.com/_rafaelgss>, <https://www.npmjs.com/~rafaelgss>
|
||||
* [__Trivikram Kamat__](https://github.com/trivikr),
|
||||
<https://x.com/trivikram>, <https://www.npmjs.com/~trivikr>
|
||||
* [__Ayoub El Khattabi__](https://github.com/AyoubElk),
|
||||
<https://x.com/ayoubelkh>, <https://www.npmjs.com/~ayoubelk>
|
||||
* [__Cemre Mengu__](https://github.com/cemremengu),
|
||||
<https://x.com/cemremengu>, <https://www.npmjs.com/~cemremengu>
|
||||
* [__Salman Mitha__](https://github.com/salmanm),
|
||||
<https://www.npmjs.com/~salmanm>
|
||||
* [__Nathan Woltman__](https://github.com/nwoltman),
|
||||
<https://x.com/NathanWoltman>, <https://www.npmjs.com/~nwoltman>
|
||||
|
||||
## Hosted by
|
||||
|
||||
@@ -381,7 +385,7 @@ to join this group by Lead Maintainers.
|
||||
src="https://github.com/openjs-foundation/artwork/blob/main/openjs_foundation/openjs_foundation-logo-horizontal-color.png?raw=true"
|
||||
width="250px;"/>](https://openjsf.org/projects)
|
||||
|
||||
We are a [At-Large
|
||||
We are an [At-Large
|
||||
Project](https://github.com/openjs-foundation/cross-project-council/blob/HEAD/PROJECT_PROGRESSION.md#at-large-projects)
|
||||
in the [OpenJS Foundation](https://openjsf.org/).
|
||||
|
||||
@@ -391,7 +395,7 @@ Support this project by becoming a [SPONSOR](./SPONSORS.md)!
|
||||
Fastify has an [Open Collective](https://opencollective.com/fastify)
|
||||
page where we accept and manage financial contributions.
|
||||
|
||||
## Acknowledgements
|
||||
## Acknowledgments
|
||||
|
||||
This project is kindly sponsored by:
|
||||
- [NearForm](https://nearform.com)
|
||||
@@ -400,8 +404,8 @@ This project is kindly sponsored by:
|
||||
Past Sponsors:
|
||||
- [LetzDoIt](https://www.letzdoitapp.com/)
|
||||
|
||||
This list includes all companies that support one or more of the team members
|
||||
in the maintenance of this project.
|
||||
This list includes all companies that support one or more team members
|
||||
in maintaining this project.
|
||||
|
||||
## License
|
||||
|
||||
@@ -413,3 +417,6 @@ dependencies:
|
||||
- ISC
|
||||
- BSD-3-Clause
|
||||
- BSD-2-Clause
|
||||
|
||||
[hd-link]: https://www.herodevs.com/support/fastify-nes?utm_source=fastify&utm_medium=link&utm_campaign=github_readme
|
||||
[lts-link]: https://fastify.dev/docs/latest/Reference/LTS/
|
||||
|
||||
210
backend/node_modules/fastify/SECURITY.md
generated
vendored
210
backend/node_modules/fastify/SECURITY.md
generated
vendored
@@ -1,4 +1,210 @@
|
||||
# Security Policy
|
||||
|
||||
Please see Fastify's [organization-wide security policy
|
||||
](https://github.com/fastify/.github/blob/main/SECURITY.md).
|
||||
This document describes the management of vulnerabilities for the Fastify
|
||||
project and its official plugins.
|
||||
|
||||
## Threat Model
|
||||
|
||||
Fastify's threat model extends the
|
||||
[Node.js threat model](https://github.com/nodejs/node/blob/main/SECURITY.md#the-nodejs-threat-model).
|
||||
|
||||
**Trusted:** Application code (plugins, handlers, hooks, schemas), configuration,
|
||||
and the runtime environment.
|
||||
|
||||
**Untrusted:** All network input (HTTP headers, body, query strings, URL
|
||||
parameters).
|
||||
|
||||
### Examples of Vulnerabilities
|
||||
|
||||
- Parsing flaws that bypass validation or security controls
|
||||
- DoS through malformed input to Fastify's core
|
||||
- Bypasses of built-in protections (prototype poisoning, schema validation)
|
||||
|
||||
### Examples of Non-Vulnerabilities
|
||||
|
||||
The following are **not** considered vulnerabilities in Fastify:
|
||||
|
||||
- **Application code vulnerabilities**: XSS, SQL injection, or other flaws in
|
||||
user-written route handlers, hooks, or plugins
|
||||
- **Malicious application code**: Issues caused by intentionally malicious
|
||||
plugins or handlers (application code is trusted)
|
||||
- **Validation schema issues**: Weak or incorrect schemas provided by developers
|
||||
(schemas are trusted)
|
||||
- **ReDoS in user patterns**: Regular expression DoS in user-provided regex
|
||||
patterns for routes or validation
|
||||
- **Missing security features**: Lack of rate limiting, authentication, or
|
||||
authorization (these are application-level concerns)
|
||||
- **Configuration mistakes**: Security issues arising from developer
|
||||
misconfiguration (configuration is trusted)
|
||||
- **Third-party dependencies**: Vulnerabilities in npm packages used by the
|
||||
application (not Fastify core dependencies)
|
||||
- **Resource exhaustion from handlers**: DoS caused by expensive operations in
|
||||
user route handlers
|
||||
- **Information disclosure by design**: Exposing error details or stack traces
|
||||
explicitly enabled via configuration options
|
||||
|
||||
## Reporting vulnerabilities
|
||||
|
||||
Individuals who find potential vulnerabilities in Fastify are invited to
|
||||
complete a vulnerability report via the dedicated pages:
|
||||
|
||||
1. [HackerOne](https://hackerone.com/fastify)
|
||||
2. [GitHub Security Advisory](https://github.com/fastify/fastify/security/advisories/new)
|
||||
|
||||
### Strict measures when reporting vulnerabilities
|
||||
|
||||
It is of the utmost importance that you read carefully and follow these
|
||||
guidelines to ensure the ecosystem as a whole isn't disrupted due to improperly
|
||||
reported vulnerabilities:
|
||||
|
||||
* Avoid creating new "informative" reports. Only create new
|
||||
reports on a vulnerability if you are absolutely sure this should be
|
||||
tagged as an actual vulnerability. Third-party vendors and individuals are
|
||||
tracking any new vulnerabilities reported in HackerOne or GitHub and will flag
|
||||
them as such for their customers (think about snyk, npm audit, ...).
|
||||
* Security reports should never be created and triaged by the same person. If
|
||||
you are creating a report for a vulnerability that you found, or on
|
||||
behalf of someone else, there should always be a 2nd Security Team member who
|
||||
triages it. If in doubt, invite more Fastify Collaborators to help triage the
|
||||
validity of the report. In any case, the report should follow the same process
|
||||
as outlined below of inviting the maintainers to review and accept the
|
||||
vulnerability.
|
||||
* ***Do not*** attempt to show CI/CD vulnerabilities by creating new pull
|
||||
requests to any of the Fastify organization's repositories. Doing so will
|
||||
result in a [content report][cr] to GitHub as an unsolicited exploit.
|
||||
The proper way to provide such reports is by creating a new repository,
|
||||
configured in the same manner as the repository you would like to submit
|
||||
a report about, and with a pull request to your own repository showing
|
||||
the proof of concept.
|
||||
|
||||
[cr]: https://docs.github.com/en/communities/maintaining-your-safety-on-github/reporting-abuse-or-spam#reporting-an-issue-or-pull-request
|
||||
|
||||
### Vulnerabilities found outside this process
|
||||
|
||||
⚠ The Fastify project does not support any reporting outside the process mentioned
|
||||
in this document.
|
||||
|
||||
## Handling vulnerability reports
|
||||
|
||||
When a potential vulnerability is reported, the following actions are taken:
|
||||
|
||||
### Triage
|
||||
|
||||
**Delay:** 4 business days
|
||||
|
||||
Within 4 business days, a member of the security team provides a first answer to
|
||||
the individual who submitted the potential vulnerability. The possible responses
|
||||
can be:
|
||||
|
||||
* **Acceptance**: what was reported is considered as a new vulnerability
|
||||
* **Rejection**: what was reported is not considered as a new vulnerability
|
||||
* **Need more information**: the security team needs more information in order to
|
||||
evaluate what was reported.
|
||||
|
||||
Triaging should include updating issue fields:
|
||||
* Asset - set/create the module affected by the report
|
||||
* Severity - TBD, currently left empty
|
||||
|
||||
Reference: [HackerOne: Submitting
|
||||
Reports](https://docs.hackerone.com/hackers/submitting-reports.html)
|
||||
|
||||
### Correction follow-up
|
||||
|
||||
**Delay:** 90 days
|
||||
|
||||
When a vulnerability is confirmed, a member of the security team volunteers to
|
||||
follow up on this report.
|
||||
|
||||
With the help of the individual who reported the vulnerability, they contact the
|
||||
maintainers of the vulnerable package to make them aware of the vulnerability.
|
||||
The maintainers can be invited as participants to the reported issue.
|
||||
|
||||
With the package maintainer, they define a release date for the publication of
|
||||
the vulnerability. Ideally, this release date should not happen before the
|
||||
package has been patched.
|
||||
|
||||
The report's vulnerable versions upper limit should be set to:
|
||||
* `*` if there is no fixed version available by the time of publishing the
|
||||
report.
|
||||
* the last vulnerable version. For example: `<=1.2.3` if a fix exists in `1.2.4`
|
||||
|
||||
### Publication
|
||||
|
||||
**Delay:** 90 days
|
||||
|
||||
Within 90 days after the triage date, the vulnerability must be made public.
|
||||
|
||||
**Severity**: Vulnerability severity is assessed using [CVSS
|
||||
v.3](https://www.first.org/cvss/user-guide). More information can be found on
|
||||
[HackerOne documentation](https://docs.hackerone.com/hackers/severity.html)
|
||||
|
||||
If the package maintainer is actively developing a patch, an additional delay
|
||||
can be added with the approval of the security team and the individual who
|
||||
reported the vulnerability.
|
||||
|
||||
At this point, a CVE should be requested through the selected platform through
|
||||
the UI, which should include the Report ID and a summary.
|
||||
|
||||
Within HackerOne, this is handled through a "public disclosure request".
|
||||
|
||||
Reference: [HackerOne:
|
||||
Disclosure](https://docs.hackerone.com/hackers/disclosure.html)
|
||||
|
||||
### Secondary Contact
|
||||
|
||||
If you do not receive an acknowledgment of your report within 6 business days,
|
||||
or if you cannot find a private security contact for the project, you may
|
||||
contact the OpenJS Foundation CNA at `security@lists.openjsf.org` for
|
||||
assistance.
|
||||
|
||||
The CNA can help ensure your report is properly acknowledged, assist with
|
||||
coordinating disclosure timelines, and assign CVEs when necessary. This is a
|
||||
support mechanism to ensure security reports are handled appropriately across
|
||||
all OpenJS Foundation projects.
|
||||
|
||||
## The Fastify Security team
|
||||
|
||||
The core team is responsible for the management of the security program and
|
||||
this policy and process.
|
||||
|
||||
Members of this team are expected to keep all information that they have
|
||||
privileged access to by being on the team completely private to the team. This
|
||||
includes agreeing to not notify anyone outside the team of issues that have not
|
||||
yet been disclosed publicly, including the existence of issues, expectations of
|
||||
upcoming releases, and patching of any issues other than in the process of their
|
||||
work as a member of the Fastify Core team.
|
||||
|
||||
### Members
|
||||
|
||||
* [__Matteo Collina__](https://github.com/mcollina),
|
||||
<https://x.com/matteocollina>, <https://www.npmjs.com/~matteo.collina>
|
||||
* [__Tomas Della Vedova__](https://github.com/delvedor),
|
||||
<https://x.com/delvedor>, <https://www.npmjs.com/~delvedor>
|
||||
* [__Vincent Le Goff__](https://github.com/zekth)
|
||||
* [__KaKa Ng__](https://github.com/climba03003)
|
||||
* [__James Sumners__](https://github.com/jsumners),
|
||||
<https://x.com/jsumners79>, <https://www.npmjs.com/~jsumners>
|
||||
|
||||
## OpenSSF CII Best Practices
|
||||
|
||||
[](https://bestpractices.coreinfrastructure.org/projects/7585)
|
||||
|
||||
There are three “tiers”: passing, silver, and gold.
|
||||
|
||||
### Passing
|
||||
We meet 100% of the “passing” criteria.
|
||||
|
||||
### Silver
|
||||
We meet 87% of the "silver" criteria. The gaps are as follows:
|
||||
- we do not have a DCO or a CLA process for contributions.
|
||||
- we do not currently document "the architecture (aka high-level design)"
|
||||
for our project.
|
||||
|
||||
### Gold
|
||||
We meet 70% of the “gold” criteria. The gaps are as follows:
|
||||
- we do not yet have the “silver” badge; see all the gaps above.
|
||||
- We do not include a copyright or license statement in each source file.
|
||||
Efforts are underway to change this archaic practice into a
|
||||
suggestion instead of a hard requirement.
|
||||
- There are a few unanswered questions around cryptography that are
|
||||
waiting for clarification.
|
||||
|
||||
4
backend/node_modules/fastify/SPONSORS.md
generated
vendored
4
backend/node_modules/fastify/SPONSORS.md
generated
vendored
@@ -9,13 +9,15 @@ or [GitHub Sponsors](https://github.com/sponsors/fastify)!
|
||||
|
||||
## Tier 4
|
||||
|
||||
_Be the first!_
|
||||
- [SerpApi](http://serpapi.com/)
|
||||
|
||||
## Tier 3
|
||||
|
||||
- [Mercedes-Benz Group](https://github.com/mercedes-benz)
|
||||
- [Val Town, Inc.](https://opencollective.com/valtown)
|
||||
- [Handsontable - JavaScript Data Grid](https://handsontable.com/docs/react-data-grid/?utm_source=Fastify_GH&utm_medium=sponsorship&utm_campaign=library_sponsorship_2024)
|
||||
- [Lokalise - A Localization and Translation Software Tool](https://lokalise.com/?utm_source=Fastify_GH&utm_medium=sponsorship)
|
||||
- [Lambdatest](https://www.lambdatest.com/)
|
||||
|
||||
## Tier 2
|
||||
|
||||
|
||||
5
backend/node_modules/fastify/build/build-error-serializer.js
generated
vendored
5
backend/node_modules/fastify/build/build-error-serializer.js
generated
vendored
@@ -18,10 +18,12 @@ const code = FJS({
|
||||
const file = path.join(__dirname, '..', 'lib', 'error-serializer.js')
|
||||
|
||||
const moduleCode = `// This file is autogenerated by build/build-error-serializer.js, do not edit
|
||||
/* istanbul ignore file */
|
||||
/* c8 ignore start */
|
||||
${code}
|
||||
/* c8 ignore stop */
|
||||
`
|
||||
|
||||
/* c8 ignore start */
|
||||
if (require.main === module) {
|
||||
fs.writeFileSync(file, moduleCode)
|
||||
console.log(`Saved ${file} file successfully`)
|
||||
@@ -30,3 +32,4 @@ if (require.main === module) {
|
||||
code: moduleCode
|
||||
}
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
|
||||
41
backend/node_modules/fastify/build/build-validation.js
generated
vendored
41
backend/node_modules/fastify/build/build-validation.js
generated
vendored
@@ -8,14 +8,15 @@ const path = require('node:path')
|
||||
const factory = AjvStandaloneCompiler({
|
||||
readMode: false,
|
||||
storeFunction (routeOpts, schemaValidationCode) {
|
||||
const moduleCode = `// This file is autogenerated by ${__filename.replace(__dirname, 'build')}, do not edit
|
||||
/* istanbul ignore file */
|
||||
const moduleCode = `// This file is autogenerated by build/build-validation.js, do not edit
|
||||
/* c8 ignore start */
|
||||
${schemaValidationCode}
|
||||
|
||||
module.exports.defaultInitOptions = ${JSON.stringify(defaultInitOptions)}
|
||||
/* c8 ignore stop */
|
||||
`
|
||||
|
||||
const file = path.join(__dirname, '..', 'lib', 'configValidator.js')
|
||||
const file = path.join(__dirname, '..', 'lib', 'config-validator.js')
|
||||
fs.writeFileSync(file, moduleCode)
|
||||
console.log(`Saved ${file} file successfully`)
|
||||
}
|
||||
@@ -31,18 +32,25 @@ const defaultInitOptions = {
|
||||
caseSensitive: true,
|
||||
allowUnsafeRegex: false,
|
||||
disableRequestLogging: false,
|
||||
jsonShorthand: true,
|
||||
ignoreTrailingSlash: false,
|
||||
ignoreDuplicateSlashes: false,
|
||||
maxParamLength: 100,
|
||||
onProtoPoisoning: 'error',
|
||||
onConstructorPoisoning: 'error',
|
||||
pluginTimeout: 10000,
|
||||
requestIdHeader: 'request-id',
|
||||
requestIdHeader: false,
|
||||
requestIdLogLabel: 'reqId',
|
||||
http2SessionTimeout: 72000, // 72 seconds
|
||||
exposeHeadRoutes: true,
|
||||
useSemicolonDelimiter: true
|
||||
useSemicolonDelimiter: false,
|
||||
allowErrorHandlerOverride: true, // TODO: set to false in v6
|
||||
routerOptions: {
|
||||
ignoreTrailingSlash: false,
|
||||
ignoreDuplicateSlashes: false,
|
||||
maxParamLength: 100,
|
||||
allowUnsafeRegex: false,
|
||||
useSemicolonDelimiter: false
|
||||
}
|
||||
}
|
||||
|
||||
const schema = {
|
||||
@@ -90,27 +98,26 @@ const schema = {
|
||||
ignoreTrailingSlash: { type: 'boolean', default: defaultInitOptions.ignoreTrailingSlash },
|
||||
ignoreDuplicateSlashes: { type: 'boolean', default: defaultInitOptions.ignoreDuplicateSlashes },
|
||||
disableRequestLogging: {
|
||||
type: 'boolean',
|
||||
default: false
|
||||
},
|
||||
jsonShorthand: { type: 'boolean', default: defaultInitOptions.jsonShorthand },
|
||||
maxParamLength: { type: 'integer', default: defaultInitOptions.maxParamLength },
|
||||
onProtoPoisoning: { type: 'string', default: defaultInitOptions.onProtoPoisoning },
|
||||
onConstructorPoisoning: { type: 'string', default: defaultInitOptions.onConstructorPoisoning },
|
||||
pluginTimeout: { type: 'integer', default: defaultInitOptions.pluginTimeout },
|
||||
requestIdHeader: { anyOf: [{ enum: [false] }, { type: 'string' }], default: defaultInitOptions.requestIdHeader },
|
||||
requestIdHeader: { anyOf: [{ type: 'boolean' }, { type: 'string' }], default: defaultInitOptions.requestIdHeader },
|
||||
requestIdLogLabel: { type: 'string', default: defaultInitOptions.requestIdLogLabel },
|
||||
http2SessionTimeout: { type: 'integer', default: defaultInitOptions.http2SessionTimeout },
|
||||
exposeHeadRoutes: { type: 'boolean', default: defaultInitOptions.exposeHeadRoutes },
|
||||
useSemicolonDelimiter: { type: 'boolean', default: defaultInitOptions.useSemicolonDelimiter },
|
||||
// deprecated style of passing the versioning constraint
|
||||
versioning: {
|
||||
routerOptions: {
|
||||
type: 'object',
|
||||
additionalProperties: true,
|
||||
required: ['storage', 'deriveVersion'],
|
||||
properties: {
|
||||
storage: { },
|
||||
deriveVersion: { }
|
||||
ignoreTrailingSlash: { type: 'boolean', default: defaultInitOptions.routerOptions.ignoreTrailingSlash },
|
||||
ignoreDuplicateSlashes: { type: 'boolean', default: defaultInitOptions.routerOptions.ignoreDuplicateSlashes },
|
||||
maxParamLength: { type: 'integer', default: defaultInitOptions.routerOptions.maxParamLength },
|
||||
allowUnsafeRegex: { type: 'boolean', default: defaultInitOptions.routerOptions.allowUnsafeRegex },
|
||||
useSemicolonDelimiter: { type: 'boolean', default: defaultInitOptions.routerOptions.useSemicolonDelimiter }
|
||||
}
|
||||
},
|
||||
constraints: {
|
||||
@@ -121,9 +128,9 @@ const schema = {
|
||||
additionalProperties: true,
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
storage: { },
|
||||
validate: { },
|
||||
deriveConstraint: { }
|
||||
storage: {},
|
||||
validate: {},
|
||||
deriveConstraint: {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
10
backend/node_modules/fastify/docs/Guides/Benchmarking.md
generated
vendored
10
backend/node_modules/fastify/docs/Guides/Benchmarking.md
generated
vendored
@@ -1,18 +1,18 @@
|
||||
<h1 align="center">Fastify</h1>
|
||||
|
||||
## Benchmarking
|
||||
Benchmarking is important if you want to measure how a change can affect the
|
||||
performance of your application. We provide a simple way to benchmark your
|
||||
Benchmarking is important if you want to measure how a change can affect your
|
||||
application's performance. We provide a simple way to benchmark your
|
||||
application from the point of view of a user and contributor. The setup allows
|
||||
you to automate benchmarks in different branches and on different Node.js
|
||||
versions.
|
||||
|
||||
The modules we will use:
|
||||
- [Autocannon](https://github.com/mcollina/autocannon): A HTTP/1.1 benchmarking
|
||||
- [Autocannon](https://github.com/mcollina/autocannon): An HTTP/1.1 benchmarking
|
||||
tool written in node.
|
||||
- [Branch-comparer](https://github.com/StarpTech/branch-comparer): Checkout
|
||||
multiple git branches, execute scripts and log the results.
|
||||
- [Concurrently](https://github.com/kimmobrunfeldt/concurrently): Run commands
|
||||
multiple git branches, execute scripts, and log the results.
|
||||
- [Concurrently](https://github.com/open-cli-tools/concurrently): Run commands
|
||||
concurrently.
|
||||
- [Npx](https://github.com/npm/npx): NPM package runner used to run scripts
|
||||
against different Node.js Versions and execute local binaries. Shipped with
|
||||
|
||||
32
backend/node_modules/fastify/docs/Guides/Database.md
generated
vendored
32
backend/node_modules/fastify/docs/Guides/Database.md
generated
vendored
@@ -2,17 +2,17 @@
|
||||
|
||||
## Database
|
||||
|
||||
Fastify's ecosystem provides a handful of
|
||||
plugins for connecting to various database engines.
|
||||
This guide covers engines that have Fastify
|
||||
Fastify's ecosystem provides a handful of
|
||||
plugins for connecting to various database engines.
|
||||
This guide covers engines that have Fastify
|
||||
plugins maintained within the Fastify organization.
|
||||
|
||||
> If a plugin for your database of choice does not exist
|
||||
> you can still use the database as Fastify is database agnostic.
|
||||
> By following the examples of the database plugins listed in this guide,
|
||||
> a plugin can be written for the missing database engine.
|
||||
> If a plugin for your database of choice does not exist
|
||||
> you can still use the database as Fastify is database agnostic.
|
||||
> By following the examples of the database plugins listed in this guide,
|
||||
> a plugin can be written for the missing database engine.
|
||||
|
||||
> If you would like to write your own Fastify plugin
|
||||
> If you would like to write your own Fastify plugin
|
||||
> please take a look at the [plugins guide](./Plugins-Guide.md)
|
||||
|
||||
### [MySQL](https://github.com/fastify/fastify-mysql)
|
||||
@@ -104,8 +104,8 @@ fastify.listen({ port: 3000 }, err => {
|
||||
})
|
||||
```
|
||||
|
||||
By default `@fastify/redis` doesn't close
|
||||
the client connection when Fastify server shuts down.
|
||||
By default `@fastify/redis` doesn't close
|
||||
the client connection when Fastify server shuts down.
|
||||
To opt-in to this behavior, register the client like so:
|
||||
|
||||
```javascript
|
||||
@@ -126,7 +126,7 @@ fastify.register(require('@fastify/mongodb'), {
|
||||
// force to close the mongodb connection when app stopped
|
||||
// the default value is false
|
||||
forceClose: true,
|
||||
|
||||
|
||||
url: 'mongodb://mongo/mydb'
|
||||
})
|
||||
|
||||
@@ -178,8 +178,8 @@ fastify.listen({ port: 3000 }, err => {
|
||||
```
|
||||
|
||||
### Writing plugin for a database library
|
||||
We could write a plugin for a database
|
||||
library too (e.g. Knex, Prisma, or TypeORM).
|
||||
We could write a plugin for a database
|
||||
library too (e.g. Knex, Prisma, or TypeORM).
|
||||
We will use [Knex](https://knexjs.org/) in our example.
|
||||
|
||||
```javascript
|
||||
@@ -245,7 +245,7 @@ for Postgres, MySQL, SQL Server and SQLite. For MongoDB migrations, please check
|
||||
#### [Postgrator](https://www.npmjs.com/package/postgrator)
|
||||
|
||||
Postgrator is Node.js SQL migration tool that uses a directory of SQL scripts to
|
||||
alter the database schema. Each file an migrations folder need to follow the
|
||||
alter the database schema. Each file in a migrations folder needs to follow the
|
||||
pattern: ` [version].[action].[optional-description].sql`.
|
||||
|
||||
**version:** must be an incrementing number (e.g. `001` or a timestamp).
|
||||
@@ -281,7 +281,7 @@ async function migrate() {
|
||||
const client = new pg.Client({
|
||||
host: 'localhost',
|
||||
port: 5432,
|
||||
database: 'example',
|
||||
database: 'example',
|
||||
user: 'example',
|
||||
password: 'example',
|
||||
});
|
||||
@@ -313,7 +313,7 @@ async function migrate() {
|
||||
console.error(err)
|
||||
process.exitCode = 1
|
||||
}
|
||||
|
||||
|
||||
await client.end()
|
||||
}
|
||||
|
||||
|
||||
37
backend/node_modules/fastify/docs/Guides/Delay-Accepting-Requests.md
generated
vendored
37
backend/node_modules/fastify/docs/Guides/Delay-Accepting-Requests.md
generated
vendored
@@ -77,8 +77,8 @@ server.get('/ping', function (request, reply) {
|
||||
})
|
||||
|
||||
server.post('/webhook', function (request, reply) {
|
||||
// It's good practice to validate webhook requests really come from
|
||||
// whoever you expect. This is skipped in this sample for the sake
|
||||
// It's good practice to validate webhook requests come from
|
||||
// who you expect. This is skipped in this sample for the sake
|
||||
// of simplicity
|
||||
|
||||
const { magicKey } = request.body
|
||||
@@ -103,7 +103,7 @@ server.get('/v1*', async function (request, reply) {
|
||||
}
|
||||
})
|
||||
|
||||
server.decorate('magicKey', null)
|
||||
server.decorate('magicKey')
|
||||
|
||||
server.listen({ port: '1234' }, () => {
|
||||
provider.thirdPartyMagicKeyGenerator(USUAL_WAIT_TIME_MS)
|
||||
@@ -303,7 +303,7 @@ async function setup(fastify) {
|
||||
fastify.server.on('listening', doMagic)
|
||||
|
||||
// Set up the placeholder for the magicKey
|
||||
fastify.decorate('magicKey', null)
|
||||
fastify.decorate('magicKey')
|
||||
|
||||
// Our magic -- important to make sure errors are handled. Beware of async
|
||||
// functions outside `try/catch` blocks
|
||||
@@ -406,7 +406,7 @@ https://nodejs.org/api/net.html#event-listening). We use that to reach out to
|
||||
our provider as soon as possible, with the `doMagic` function.
|
||||
|
||||
```js
|
||||
fastify.decorate('magicKey', null)
|
||||
fastify.decorate('magicKey')
|
||||
```
|
||||
|
||||
The `magicKey` decoration is also part of the plugin now. We initialize it with
|
||||
@@ -448,10 +448,10 @@ have the possibility of giving the customer meaningful information, like how
|
||||
long they should wait before retrying the request. Going even further, by
|
||||
issuing a [`503` status
|
||||
code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/503) we're
|
||||
signaling to our infrastructure components (namely load balancers) we're still
|
||||
not ready to take incoming requests and they should redirect traffic to other
|
||||
instances, if available, besides in how long we estimate that will be solved.
|
||||
All of that in a few simple lines!
|
||||
signaling to our infrastructure components (namely load balancers) that we're
|
||||
still not ready to take incoming requests and they should redirect traffic to
|
||||
other instances, if available. Additionally, we are providing a `Retry-After`
|
||||
header with the time in milliseconds the client should wait before retrying.
|
||||
|
||||
It's noteworthy that we didn't use the `fastify-plugin` wrapper in the `delay`
|
||||
factory. That's because we wanted the `onRequest` hook to only be set within
|
||||
@@ -524,14 +524,17 @@ Retry-After: 5000
|
||||
}
|
||||
```
|
||||
|
||||
Then we attempt a new request (`req-2`), which was a `GET /ping`. As expected,
|
||||
Then we attempted a new request (`req-2`), which was a `GET /ping`. As expected,
|
||||
since that was not one of the requests we asked our plugin to filter, it
|
||||
succeeded. That could also be used as means of informing an interested party
|
||||
whether or not we were ready to serve requests (although `/ping` is more
|
||||
commonly associated with *liveness* checks and that would be the responsibility
|
||||
of a *readiness* check -- the curious reader can get more info on these terms
|
||||
[here](https://cloud.google.com/blog/products/containers-kubernetes/kubernetes-best-practices-setting-up-health-checks-with-readiness-and-liveness-probes))
|
||||
with the `ready` field. Below is the response for that request:
|
||||
succeeded. That could also be used as a means of informing an interested party
|
||||
whether or not we were ready to serve requests with the `ready` field. Although
|
||||
`/ping` is more commonly associated with *liveness* checks and that would be
|
||||
the responsibility of a *readiness* check. The curious reader can get more info
|
||||
on these terms in the article
|
||||
["Kubernetes best practices: Setting up health checks with readiness and liveness probes"](
|
||||
https://cloud.google.com/blog/products/containers-kubernetes/kubernetes-best-practices-setting-up-health-checks-with-readiness-and-liveness-probes).
|
||||
|
||||
Below is the response to that request:
|
||||
|
||||
```sh
|
||||
HTTP/1.1 200 OK
|
||||
@@ -547,7 +550,7 @@ Keep-Alive: timeout=5
|
||||
}
|
||||
```
|
||||
|
||||
After that there were more interesting log messages:
|
||||
After that, there were more interesting log messages:
|
||||
|
||||
<!-- markdownlint-disable -->
|
||||
```sh
|
||||
|
||||
56
backend/node_modules/fastify/docs/Guides/Detecting-When-Clients-Abort.md
generated
vendored
56
backend/node_modules/fastify/docs/Guides/Detecting-When-Clients-Abort.md
generated
vendored
@@ -4,30 +4,30 @@
|
||||
|
||||
## Introduction
|
||||
|
||||
Fastify provides request events to trigger at certain points in a request's
|
||||
lifecycle. However, there isn't a built-in mechanism to
|
||||
detect unintentional client disconnection scenarios such as when the client's
|
||||
Fastify provides request events to trigger at certain points in a request's
|
||||
lifecycle. However, there isn't a built-in mechanism to
|
||||
detect unintentional client disconnection scenarios such as when the client's
|
||||
internet connection is interrupted. This guide covers methods to detect if
|
||||
and when a client intentionally aborts a request.
|
||||
|
||||
Keep in mind, Fastify's `clientErrorHandler` is not designed to detect when a
|
||||
client aborts a request. This works in the same way as the standard Node HTTP
|
||||
module, which triggers the `clientError` event when there is a bad request or
|
||||
exceedingly large header data. When a client aborts a request, there is no
|
||||
Keep in mind, Fastify's `clientErrorHandler` is not designed to detect when a
|
||||
client aborts a request. This works in the same way as the standard Node HTTP
|
||||
module, which triggers the `clientError` event when there is a bad request or
|
||||
exceedingly large header data. When a client aborts a request, there is no
|
||||
error on the socket and the `clientErrorHandler` will not be triggered.
|
||||
|
||||
## Solution
|
||||
|
||||
### Overview
|
||||
|
||||
The proposed solution is a possible way of detecting when a client
|
||||
intentionally aborts a request, such as when a browser is closed or the HTTP
|
||||
request is aborted from your client application. If there is an error in your
|
||||
application code that results in the server crashing, you may require
|
||||
The proposed solution is a possible way of detecting when a client
|
||||
intentionally aborts a request, such as when a browser is closed or the HTTP
|
||||
request is aborted from your client application. If there is an error in your
|
||||
application code that results in the server crashing, you may require
|
||||
additional logic to avoid a false abort detection.
|
||||
|
||||
The goal here is to detect when a client intentionally aborts a connection
|
||||
so your application logic can proceed accordingly. This can be useful for
|
||||
The goal here is to detect when a client intentionally aborts a connection
|
||||
so your application logic can proceed accordingly. This can be useful for
|
||||
logging purposes or halting business logic.
|
||||
|
||||
### Hands-on
|
||||
@@ -78,10 +78,10 @@ const start = async () => {
|
||||
start()
|
||||
```
|
||||
|
||||
Our code is setting up a Fastify server which includes the following
|
||||
Our code is setting up a Fastify server which includes the following
|
||||
functionality:
|
||||
|
||||
- Accepting requests at http://localhost:3000, with a 3 second delayed response
|
||||
- Accepting requests at `http://localhost:3000`, with a 3 second delayed response
|
||||
of `{ ok: true }`.
|
||||
- An onRequest hook that triggers when every request is received.
|
||||
- Logic that triggers in the hook when the request is closed.
|
||||
@@ -108,7 +108,7 @@ app.get('/', async (request, reply) => {
|
||||
})
|
||||
```
|
||||
|
||||
At any point in your business logic, you can check if the request has been
|
||||
At any point in your business logic, you can check if the request has been
|
||||
aborted and perform alternative actions.
|
||||
|
||||
```js
|
||||
@@ -122,14 +122,14 @@ app.get('/', async (request, reply) => {
|
||||
})
|
||||
```
|
||||
|
||||
A benefit to adding this in your application code is that you can log Fastify
|
||||
details such as the reqId, which may be unavailable in lower-level code that
|
||||
A benefit to adding this in your application code is that you can log Fastify
|
||||
details such as the reqId, which may be unavailable in lower-level code that
|
||||
only has access to the raw request information.
|
||||
|
||||
### Testing
|
||||
|
||||
To test this functionality you can use an app like Postman and cancel your
|
||||
request within 3 seconds. Alternatively, you can use Node to send an HTTP
|
||||
To test this functionality you can use an app like Postman and cancel your
|
||||
request within 3 seconds. Alternatively, you can use Node to send an HTTP
|
||||
request with logic to abort the request before 3 seconds. Example:
|
||||
|
||||
```js
|
||||
@@ -151,7 +151,7 @@ setTimeout(() => {
|
||||
}, 1000);
|
||||
```
|
||||
|
||||
With either approach, you should see the Fastify log appear at the moment the
|
||||
With either approach, you should see the Fastify log appear at the moment the
|
||||
request is aborted.
|
||||
|
||||
## Conclusion
|
||||
@@ -160,13 +160,13 @@ Specifics of the implementation will vary from one problem to another, but the
|
||||
main goal of this guide was to show a very specific use case of an issue that
|
||||
could be solved within Fastify's ecosystem.
|
||||
|
||||
You can listen to the request close event and determine if the request was
|
||||
aborted or if it was successfully delivered. You can implement this solution
|
||||
You can listen to the request close event and determine if the request was
|
||||
aborted or if it was successfully delivered. You can implement this solution
|
||||
in an onRequest hook or directly in an individual route.
|
||||
|
||||
This approach will not trigger in the event of internet disruption, and such
|
||||
detection would require additional business logic. If you have flawed backend
|
||||
application logic that results in a server crash, then you could trigger a
|
||||
false detection. The `clientErrorHandler`, either by default or with custom
|
||||
logic, is not intended to handle this scenario and will not trigger when the
|
||||
This approach will not trigger in the event of internet disruption, and such
|
||||
detection would require additional business logic. If you have flawed backend
|
||||
application logic that results in a server crash, then you could trigger a
|
||||
false detection. The `clientErrorHandler`, either by default or with custom
|
||||
logic, is not intended to handle this scenario and will not trigger when the
|
||||
client aborts a request.
|
||||
|
||||
107
backend/node_modules/fastify/docs/Guides/Ecosystem.md
generated
vendored
107
backend/node_modules/fastify/docs/Guides/Ecosystem.md
generated
vendored
@@ -12,8 +12,6 @@ section.
|
||||
[accepts](https://www.npmjs.com/package/accepts) in your request object.
|
||||
- [`@fastify/accepts-serializer`](https://github.com/fastify/fastify-accepts-serializer)
|
||||
to serialize to output according to the `Accept` header.
|
||||
- [`@fastify/any-schema`](https://github.com/fastify/any-schema-you-like) Save
|
||||
multiple schemas and decide which one to use to serialize the payload.
|
||||
- [`@fastify/auth`](https://github.com/fastify/fastify-auth) Run multiple auth
|
||||
functions in Fastify.
|
||||
- [`@fastify/autoload`](https://github.com/fastify/fastify-autoload) Require all
|
||||
@@ -42,11 +40,6 @@ section.
|
||||
plugin for adding
|
||||
[CSRF](https://en.wikipedia.org/wiki/Cross-site_request_forgery) protection to
|
||||
Fastify.
|
||||
- [`@fastify/diagnostics-channel`](https://github.com/fastify/fastify-diagnostics-channel)
|
||||
Plugin to deal with `diagnostics_channel` on Fastify
|
||||
- [`@fastify/early-hints`](https://github.com/fastify/fastify-early-hints) Plugin
|
||||
to add HTTP 103 feature based on [RFC
|
||||
8297](https://datatracker.ietf.org/doc/html/rfc8297).
|
||||
- [`@fastify/elasticsearch`](https://github.com/fastify/fastify-elasticsearch)
|
||||
Plugin to share the same ES client.
|
||||
- [`@fastify/env`](https://github.com/fastify/fastify-env) Load and check
|
||||
@@ -91,6 +84,8 @@ section.
|
||||
[`simple-oauth2`](https://github.com/lelylan/simple-oauth2).
|
||||
- [`@fastify/one-line-logger`](https://github.com/fastify/one-line-logger) Formats
|
||||
Fastify's logs into a nice one-line message.
|
||||
- [`@fastify/otel`](https://github.com/fastify/otel) OpenTelemetry
|
||||
instrumentation library.
|
||||
- [`@fastify/passport`](https://github.com/fastify/fastify-passport) Use Passport
|
||||
strategies to authenticate requests and protect route.
|
||||
- [`@fastify/postgres`](https://github.com/fastify/fastify-postgres) Fastify
|
||||
@@ -124,8 +119,8 @@ section.
|
||||
HTTP errors and assertions, but also more request and reply methods.
|
||||
- [`@fastify/session`](https://github.com/fastify/session) a session plugin for
|
||||
Fastify.
|
||||
- [`@fastify/soap-client`](https://github.com/fastify/fastify-soap-client) a SOAP
|
||||
client plugin for Fastify.
|
||||
- [`@fastify/sse`](https://github.com/fastify/sse) Plugin for Server-Sent Events
|
||||
(SSE) support in Fastify.
|
||||
- [`@fastify/static`](https://github.com/fastify/fastify-static) Plugin for
|
||||
serving static files as fast as possible.
|
||||
- [`@fastify/swagger`](https://github.com/fastify/fastify-swagger) Plugin for
|
||||
@@ -159,8 +154,22 @@ section.
|
||||
|
||||
#### [Community](#community)
|
||||
|
||||
> ℹ️ Note:
|
||||
> Fastify community plugins are part of the broader community efforts,
|
||||
> and we are thankful for these contributions. However, they are not
|
||||
> maintained by the Fastify team.
|
||||
> Use them at your own discretion.
|
||||
> If you find malicious code, please
|
||||
> [open an issue](https://github.com/fastify/fastify/issues/new/choose) or
|
||||
> submit a PR to remove the plugin from the list.
|
||||
|
||||
- [`@aaroncadillac/crudify-mongo`](https://github.com/aaroncadillac/crudify-mongo)
|
||||
A simple way to add a crud in your fastify project.
|
||||
- [`@applicazza/fastify-nextjs`](https://github.com/applicazza/fastify-nextjs)
|
||||
Alternate Fastify and Next.js integration.
|
||||
- [`@attaryz/fastify-devtools`](https://github.com/attaryz/fastify-devtools)
|
||||
Development tools plugin for Fastify with live request dashboard, replay
|
||||
capabilities, and metrics tracking.
|
||||
- [`@blastorg/fastify-aws-dynamodb-cache`](https://github.com/blastorg/fastify-aws-dynamodb-cache)
|
||||
A plugin to help with caching API responses using AWS DynamoDB.
|
||||
- [`@clerk/fastify`](https://github.com/clerkinc/javascript/tree/main/packages/fastify)
|
||||
@@ -173,13 +182,12 @@ section.
|
||||
close the server gracefully on `SIGINT` and `SIGTERM` signals.
|
||||
- [`@eropple/fastify-openapi3`](https://github.com/eropple/fastify-openapi3) Provides
|
||||
easy, developer-friendly OpenAPI 3.1 specs + doc explorer based on your routes.
|
||||
- [`@ethicdevs/fastify-custom-session`](https://github.com/EthicDevs/fastify-custom-session)
|
||||
A plugin lets you use session and decide only where to load/save from/to. Has
|
||||
great TypeScript support + built-in adapters for common ORMs/databases (Firebase,
|
||||
Prisma Client, Postgres (wip), InMemory) and you can easily make your own adapter!
|
||||
- [`@ethicdevs/fastify-git-server`](https://github.com/EthicDevs/fastify-git-server)
|
||||
A plugin to easily create git server and make one/many Git repositories available
|
||||
for clone/fetch/push through the standard `git` (over http) commands.
|
||||
|
||||
|
||||
- [`@exortek/fastify-mongo-sanitize`](https://github.com/ExorTek/fastify-mongo-sanitize)
|
||||
A Fastify plugin that protects against No(n)SQL injection by sanitizing data.
|
||||
- [`@exortek/remix-fastify`](https://github.com/ExorTek/remix-fastify)
|
||||
Fastify plugin for Remix.
|
||||
- [`@fastify-userland/request-id`](https://github.com/fastify-userland/request-id)
|
||||
Fastify Request ID Plugin
|
||||
- [`@fastify-userland/typeorm-query-runner`](https://github.com/fastify-userland/typeorm-query-runner)
|
||||
@@ -191,14 +199,16 @@ section.
|
||||
Run REST APIs and other web applications using your existing Node.js
|
||||
application framework (Express, Koa, Hapi and Fastify), on top of AWS Lambda,
|
||||
Huawei and many other clouds.
|
||||
- [`@hey-api/openapi-ts`](https://heyapi.dev/openapi-ts/plugins/fastify)
|
||||
The OpenAPI to TypeScript codegen. Generate clients, SDKs, validators, and more.
|
||||
- [`@immobiliarelabs/fastify-metrics`](https://github.com/immobiliare/fastify-metrics)
|
||||
Minimalistic and opinionated plugin that collects usage/process metrics and
|
||||
dispatches to [statsd](https://github.com/statsd/statsd).
|
||||
- [`@immobiliarelabs/fastify-sentry`](https://github.com/immobiliare/fastify-sentry)
|
||||
Sentry errors handler that just works! Install, add your DSN and you're good
|
||||
to go!
|
||||
A plugin to implement [Lyra](https://github.com/nearform/lyra) search engine
|
||||
on Fastify
|
||||
- [`@inaiat/fastify-papr`](https://github.com/inaiat/fastify-papr)
|
||||
A plugin to integrate [Papr](https://github.com/plexinc/papr),
|
||||
the MongoDB ORM for TypeScript & MongoDB, with Fastify.
|
||||
- [`@jerome1337/fastify-enforce-routes-pattern`](https://github.com/Jerome1337/fastify-enforce-routes-pattern)
|
||||
A Fastify plugin that enforces naming pattern for routes path.
|
||||
- [`@joggr/fastify-prisma`](https://github.com/joggrdocs/fastify-prisma)
|
||||
A plugin for accessing an instantiated PrismaClient on your server.
|
||||
- [`@mgcrea/fastify-graceful-exit`](https://github.com/mgcrea/fastify-graceful-exit)
|
||||
@@ -213,13 +223,15 @@ section.
|
||||
Fast sodium-based crypto for @mgcrea/fastify-session
|
||||
- [`@mgcrea/pino-pretty-compact`](https://github.com/mgcrea/pino-pretty-compact)
|
||||
A custom compact pino-base prettifier
|
||||
- [`@scalar/fastify-api-reference`](https://github.com/scalar/scalar/tree/main/packages/fastify-api-reference)
|
||||
- [`@pybot/fastify-autoload`](https://github.com/kunal097/fastify-autoload)
|
||||
Plugin to generate routes automatically with valid json content
|
||||
- [`@scalar/fastify-api-reference`](https://github.com/scalar/scalar/tree/main/integrations/fastify)
|
||||
Beautiful OpenAPI/Swagger API references for Fastify
|
||||
- [`@trubavuong/fastify-seaweedfs`](https://github.com/trubavuong/fastify-seaweedfs)
|
||||
SeaweedFS for Fastify
|
||||
- [`apitally`](https://github.com/apitally/nodejs-client) Fastify plugin to
|
||||
integrate with [Apitally](https://apitally.io), a simple API monitoring &
|
||||
API key management solution.
|
||||
- [`apitally`](https://github.com/apitally/apitally-js) Fastify plugin to
|
||||
integrate with [Apitally](https://apitally.io/fastify), an API analytics,
|
||||
logging and monitoring tool.
|
||||
- [`arecibo`](https://github.com/nucleode/arecibo) Fastify ping responder for
|
||||
Kubernetes Liveness and Readiness Probes.
|
||||
- [`aws-xray-sdk-fastify`](https://github.com/aws/aws-xray-sdk-node/tree/master/sdk_contrib/fastify)
|
||||
@@ -229,6 +241,9 @@ section.
|
||||
request IDs into your logs.
|
||||
- [`electron-server`](https://github.com/anonrig/electron-server) A plugin for
|
||||
using Fastify without the need of consuming a port on Electron apps.
|
||||
- [`elements-fastify`](https://github.com/rohitsoni007/elements-fastify) Fastify
|
||||
Plugin for Stoplight Elements API Documentation using
|
||||
openapi swagger json yml.
|
||||
- [`fast-water`](https://github.com/tswayne/fast-water) A Fastify plugin for
|
||||
waterline. Decorates Fastify with waterline models.
|
||||
- [`fastify-204`](https://github.com/Shiva127/fastify-204) Fastify plugin that
|
||||
@@ -252,7 +267,7 @@ section.
|
||||
plugin to authenticate HTTP requests based on API key and signature
|
||||
- [`fastify-appwrite`](https://github.com/Dev-Manny/fastify-appwrite) Fastify
|
||||
Plugin for interacting with Appwrite server.
|
||||
- [`fastify-asyncforge`](https://github.com/mcollina/fastify-asyncforge) Plugin
|
||||
- [`fastify-asyncforge`](https://github.com/mcollina/fastify-asyncforge) Plugin
|
||||
to access Fastify instance, logger, request and reply from Node.js [Async
|
||||
Local Storage](https://nodejs.org/api/async_context.html#class-asynclocalstorage).
|
||||
- [`fastify-at-mysql`](https://github.com/mateonunez/fastify-at-mysql) Fastify
|
||||
@@ -280,7 +295,7 @@ section.
|
||||
development servers that require Babel transformations of JavaScript sources.
|
||||
- [`fastify-bcrypt`](https://github.com/beliven-it/fastify-bcrypt) A Bcrypt hash
|
||||
generator & checker.
|
||||
- [`fastify-better-sqlite3`](https://github.com/punkish/fastify-better-sqlite3)
|
||||
- [`fastify-better-sqlite3`](https://github.com/punkish/fastify-better-sqlite3)
|
||||
Plugin for better-sqlite3.
|
||||
- [`fastify-blipp`](https://github.com/PavelPolyakov/fastify-blipp) Prints your
|
||||
routes to the console, so you definitely know which endpoints are available.
|
||||
@@ -292,7 +307,7 @@ section.
|
||||
to add [bree](https://github.com/breejs/bree) support.
|
||||
- [`fastify-bugsnag`](https://github.com/ZigaStrgar/fastify-bugsnag) Fastify plugin
|
||||
to add support for [Bugsnag](https://www.bugsnag.com/) error reporting.
|
||||
- [`fastify-cacheman`](https://gitlab.com/aalfiann/fastify-cacheman)
|
||||
- [`fastify-cacheman`](https://gitlab.com/aalfiann/fastify-cacheman)
|
||||
Small and efficient cache provider for Node.js with In-memory, File, Redis
|
||||
and MongoDB engines for Fastify
|
||||
- [`fastify-casbin`](https://github.com/nearform/fastify-casbin) Casbin support
|
||||
@@ -347,7 +362,7 @@ section.
|
||||
- [`fastify-event-bus`](https://github.com/Shiva127/fastify-event-bus) Event bus
|
||||
support for Fastify. Built upon [js-event-bus](https://github.com/bcerati/js-event-bus).
|
||||
- [`fastify-evervault`](https://github.com/Briscoooe/fastify-evervault/) Fastify
|
||||
plugin for instantiating and encapsulating the
|
||||
plugin for instantiating and encapsulating the
|
||||
[Evervault](https://evervault.com/) client.
|
||||
- [`fastify-explorer`](https://github.com/Eomm/fastify-explorer) Get control of
|
||||
your decorators across all the encapsulated contexts.
|
||||
@@ -356,7 +371,7 @@ section.
|
||||
- [`fastify-feature-flags`](https://gitlab.com/m03geek/fastify-feature-flags)
|
||||
Fastify feature flags plugin with multiple providers support (e.g. env,
|
||||
[config](https://lorenwest.github.io/node-config/),
|
||||
[unleash](https://unleash.github.io/)).
|
||||
[unleash](https://github.com/Unleash/unleash)).
|
||||
- [`fastify-file-routes`](https://github.com/spa5k/fastify-file-routes) Get
|
||||
Next.js based file system routing into fastify.
|
||||
- [`fastify-file-upload`](https://github.com/huangang/fastify-file-upload)
|
||||
@@ -447,12 +462,16 @@ section.
|
||||
middlewares into Fastify plugins
|
||||
- [`fastify-kubernetes`](https://github.com/greguz/fastify-kubernetes) Fastify
|
||||
Kubernetes client plugin.
|
||||
- [`fastify-kysely`](https://github.com/alenap93/fastify-kysely) Fastify
|
||||
plugin for supporting Kysely type-safe query builder.
|
||||
- [`fastify-language-parser`](https://github.com/lependu/fastify-language-parser)
|
||||
Fastify plugin to parse request language.
|
||||
- [`fastify-lcache`](https://github.com/denbon05/fastify-lcache)
|
||||
Lightweight cache plugin
|
||||
- [`fastify-list-routes`](https://github.com/chuongtrh/fastify-list-routes)
|
||||
A simple plugin for Fastify to list all available routes.
|
||||
- [`fastify-lm`](https://github.com/galiprandi/fastify-lm#readme)
|
||||
Use OpenAI, Claude, Google, Deepseek, and others LMs with one Fastify plugin.
|
||||
- [`fastify-loader`](https://github.com/TheNoim/fastify-loader) Load routes from
|
||||
a directory and inject the Fastify instance in each file.
|
||||
- [`fastify-log-controller`](https://github.com/Eomm/fastify-log-controller/)
|
||||
@@ -493,6 +512,8 @@ middlewares into Fastify plugins
|
||||
[MS Graph Change Notifications webhooks](https://learn.microsoft.com/it-it/graph/change-notifications-delivery-webhooks?tabs=http).
|
||||
- [`fastify-multer`](https://github.com/fox1t/fastify-multer) Multer is a plugin
|
||||
for handling multipart/form-data, which is primarily used for uploading files.
|
||||
- [`fastify-multilingual`](https://github.com/gbrugger/fastify-multilingual) Unobtrusively
|
||||
decorates fastify request with Polyglot.js for i18n.
|
||||
- [`fastify-nats`](https://github.com/mahmed8003/fastify-nats) Plugin to share
|
||||
[NATS](https://nats.io) client across Fastify.
|
||||
- [`fastify-next-auth`](https://github.com/wobsoriano/fastify-next-auth)
|
||||
@@ -501,10 +522,7 @@ middlewares into Fastify plugins
|
||||
Add `additionalProperties: false` by default to your JSON Schemas.
|
||||
- [`fastify-no-icon`](https://github.com/jsumners/fastify-no-icon) Plugin to
|
||||
eliminate thrown errors for `/favicon.ico` requests.
|
||||
- [`fastify-normalize-request-reply`](https://github.com/ericrglass/fastify-normalize-request-reply)
|
||||
Plugin to normalize the request and reply to the Express version 4.x request
|
||||
and response, which allows use of middleware, like swagger-stats, that was
|
||||
originally written for Express.
|
||||
|
||||
- [`fastify-now`](https://github.com/yonathan06/fastify-now) Structure your
|
||||
endpoints in a folder and load them dynamically with Fastify.
|
||||
- [`fastify-nuxtjs`](https://github.com/gomah/fastify-nuxtjs) Vue server-side
|
||||
@@ -539,12 +557,17 @@ middlewares into Fastify plugins
|
||||
OSM plugin to run overpass queries by OpenStreetMap.
|
||||
- [`fastify-override`](https://github.com/matthyk/fastify-override)
|
||||
Fastify plugin to override decorators, plugins and hooks for testing purposes
|
||||
- [`fastify-passkit-webservice`](https://github.com/alexandercerutti/fastify-passkit-webservice)
|
||||
A set of Fastify plugins to integrate Apple Wallet Web Service specification
|
||||
- [`fastify-peekaboo`](https://github.com/simone-sanfratello/fastify-peekaboo)
|
||||
Fastify plugin for memoize responses by expressive settings.
|
||||
- [`fastify-permissions`](https://github.com/pckrishnadas88/fastify-permissions)
|
||||
Route-level permission middleware for Fastify supports
|
||||
custom permission checks.
|
||||
- [`fastify-piscina`](https://github.com/piscinajs/fastify-piscina) A worker
|
||||
thread pool plugin using [Piscina](https://github.com/piscinajs/piscina).
|
||||
- [`fastify-polyglot`](https://github.com/beliven-it/fastify-polyglot) A plugin to
|
||||
handle i18n using
|
||||
- [`fastify-polyglot`](https://github.com/beliven-it/fastify-polyglot) A plugin
|
||||
to handle i18n using
|
||||
[node-polyglot](https://www.npmjs.com/package/node-polyglot).
|
||||
- [`fastify-postgraphile`](https://github.com/alemagio/fastify-postgraphile)
|
||||
Plugin to integrate [PostGraphile](https://www.graphile.org/postgraphile/) in
|
||||
@@ -600,6 +623,9 @@ middlewares into Fastify plugins
|
||||
Fastify Rob-Config integration.
|
||||
- [`fastify-route-group`](https://github.com/TakNePoidet/fastify-route-group)
|
||||
Convenient grouping and inheritance of routes.
|
||||
- [`fastify-route-preset`](https://github.com/inyourtime/fastify-route-preset)
|
||||
A Fastify plugin that enables you to create route configurations that can be
|
||||
applied to multiple routes.
|
||||
- [`fastify-s3-buckets`](https://github.com/kibertoad/fastify-s3-buckets)
|
||||
Ensure the existence of defined S3 buckets on the application startup.
|
||||
- [`fastify-schema-constraint`](https://github.com/Eomm/fastify-schema-constraint)
|
||||
@@ -615,6 +641,8 @@ middlewares into Fastify plugins
|
||||
- [`fastify-server-session`](https://github.com/jsumners/fastify-server-session)
|
||||
A session plugin with support for arbitrary backing caches via
|
||||
`fastify-caching`.
|
||||
- [`fastify-ses-mailer`](https://github.com/KaranHotwani/fastify-ses-mailer) A
|
||||
Fastify plugin for sending emails via AWS SES using AWS SDK v3.
|
||||
- [`fastify-shared-schema`](https://github.com/Adibla/fastify-shared-schema) Plugin
|
||||
for sharing schemas between different routes.
|
||||
- [`fastify-slonik`](https://github.com/Unbuttun/fastify-slonik) Fastify Slonik
|
||||
@@ -656,7 +684,7 @@ middlewares into Fastify plugins
|
||||
- [`fastify-type-provider-effect-schema`](https://github.com/daotl/fastify-type-provider-effect-schema)
|
||||
Fastify
|
||||
[type provider](https://fastify.dev/docs/latest/Reference/Type-Providers/)
|
||||
for [@effect/schema](https://github.com/effect-ts/schema).
|
||||
for [@effect/schema](https://github.com/Effect-TS/effect).
|
||||
- [`fastify-type-provider-zod`](https://github.com/turkerdev/fastify-type-provider-zod)
|
||||
Fastify
|
||||
[type provider](https://fastify.dev/docs/latest/Reference/Type-Providers/)
|
||||
@@ -718,6 +746,7 @@ middlewares into Fastify plugins
|
||||
- [`typeorm-fastify-plugin`](https://github.com/jclemens24/fastify-typeorm) A simple
|
||||
and updated Typeorm plugin for use with Fastify.
|
||||
|
||||
|
||||
#### [Community Tools](#community-tools)
|
||||
|
||||
- [`@fastify-userland/workflows`](https://github.com/fastify-userland/workflows)
|
||||
@@ -726,9 +755,13 @@ middlewares into Fastify plugins
|
||||
generator by directory structure.
|
||||
- [`fastify-flux`](https://github.com/Jnig/fastify-flux) Tool for building
|
||||
Fastify APIs using decorators and convert Typescript interface to JSON Schema.
|
||||
- [`jeasx`](https://www.jeasx.dev)
|
||||
A flexible server-rendering framework built on Fastify
|
||||
that leverages asynchronous JSX to simplify web development.
|
||||
- [`simple-tjscli`](https://github.com/imjuni/simple-tjscli) CLI tool to
|
||||
generate JSON Schema from TypeScript interfaces.
|
||||
- [`vite-plugin-fastify`](https://github.com/Vanilla-IceCream/vite-plugin-fastify)
|
||||
Fastify plugin for Vite with Hot-module Replacement.
|
||||
- [`vite-plugin-fastify-routes`](https://github.com/Vanilla-IceCream/vite-plugin-fastify-routes)
|
||||
File-based routing for Fastify applications using Vite.
|
||||
|
||||
|
||||
6
backend/node_modules/fastify/docs/Guides/Fluent-Schema.md
generated
vendored
6
backend/node_modules/fastify/docs/Guides/Fluent-Schema.md
generated
vendored
@@ -55,7 +55,7 @@ fastify.post('/the/url', { schema }, handler)
|
||||
|
||||
### Reuse
|
||||
|
||||
With `fluent-json-schema` you can manipulate your schemas more easily and
|
||||
With `fluent-json-schema`, you can manipulate your schemas more easily and
|
||||
programmatically and then reuse them thanks to the `addSchema()` method. You can
|
||||
refer to the schema in two different manners that are detailed in the
|
||||
[Validation and
|
||||
@@ -122,5 +122,5 @@ const schema = { body: bodyJsonSchema }
|
||||
fastify.post('/the/url', { schema }, handler)
|
||||
```
|
||||
|
||||
NB You can mix up the `$ref-way` and the `replace-way` when using
|
||||
`fastify.addSchema`.
|
||||
> ℹ️ Note: You can mix up the `$ref-way` and the `replace-way`
|
||||
> when using `fastify.addSchema`.
|
||||
|
||||
22
backend/node_modules/fastify/docs/Guides/Getting-Started.md
generated
vendored
22
backend/node_modules/fastify/docs/Guides/Getting-Started.md
generated
vendored
@@ -106,7 +106,7 @@ of your code.
|
||||
Fastify offers an easy platform that helps to solve all of the problems outlined
|
||||
above, and more!
|
||||
|
||||
> ## Note
|
||||
> **Note**
|
||||
> The above examples, and subsequent examples in this document, default to
|
||||
> listening *only* on the localhost `127.0.0.1` interface. To listen on all
|
||||
> available IPv4 interfaces the example should be modified to listen on
|
||||
@@ -128,6 +128,9 @@ above, and more!
|
||||
>
|
||||
> When deploying to a Docker (or another type of) container using `0.0.0.0` or
|
||||
> `::` would be the easiest method for exposing the application.
|
||||
>
|
||||
> Note that when using `0.0.0.0`, the address provided in the callback argument
|
||||
> above will be the first address the wildcard refers to.
|
||||
|
||||
### Your first plugin
|
||||
<a id="first-plugin"></a>
|
||||
@@ -143,7 +146,7 @@ declaration](../Reference/Routes.md) docs).
|
||||
```js
|
||||
// ESM
|
||||
import Fastify from 'fastify'
|
||||
import firstRoute from './our-first-route'
|
||||
import firstRoute from './our-first-route.js'
|
||||
/**
|
||||
* @type {import('fastify').FastifyInstance} Instance of Fastify
|
||||
*/
|
||||
@@ -232,8 +235,8 @@ npm i fastify-plugin @fastify/mongodb
|
||||
```js
|
||||
// ESM
|
||||
import Fastify from 'fastify'
|
||||
import dbConnector from './our-db-connector'
|
||||
import firstRoute from './our-first-route'
|
||||
import dbConnector from './our-db-connector.js'
|
||||
import firstRoute from './our-first-route.js'
|
||||
|
||||
/**
|
||||
* @type {import('fastify').FastifyInstance} Instance of Fastify
|
||||
@@ -417,7 +420,7 @@ In this way, you will always have access to all of the properties declared in
|
||||
the current scope.
|
||||
|
||||
As discussed previously, Fastify offers a solid encapsulation model, to help you
|
||||
build your application as single and independent services. If you want to
|
||||
build your application as independent services. If you want to
|
||||
register a plugin only for a subset of routes, you just have to replicate the
|
||||
above structure.
|
||||
```
|
||||
@@ -450,8 +453,6 @@ Data validation is extremely important and a core concept of the framework.
|
||||
To validate incoming requests, Fastify uses [JSON
|
||||
Schema](https://json-schema.org/).
|
||||
|
||||
(JTD schemas are loosely supported, but `jsonShorthand` must be disabled first)
|
||||
|
||||
Let's look at an example demonstrating validation for routes:
|
||||
```js
|
||||
/**
|
||||
@@ -554,15 +555,16 @@ an amazing [ecosystem](./Ecosystem.md)!
|
||||
<a id="test-server"></a>
|
||||
|
||||
Fastify does not offer a testing framework, but we do recommend a way to write
|
||||
your tests that use the features and architecture of Fastify.
|
||||
your tests that uses the features and architecture of Fastify.
|
||||
|
||||
Read the [testing](./Testing.md) documentation to learn more!
|
||||
|
||||
### Run your server from CLI
|
||||
<a id="cli"></a>
|
||||
|
||||
Fastify also has CLI integration thanks to
|
||||
[fastify-cli](https://github.com/fastify/fastify-cli).
|
||||
Fastify also has CLI integration via
|
||||
[fastify-cli](https://github.com/fastify/fastify-cli),
|
||||
a separate tool for scaffolding and managing Fastify projects.
|
||||
|
||||
First, install `fastify-cli`:
|
||||
|
||||
|
||||
4
backend/node_modules/fastify/docs/Guides/Index.md
generated
vendored
4
backend/node_modules/fastify/docs/Guides/Index.md
generated
vendored
@@ -15,11 +15,11 @@ This table of contents is in alphabetical order.
|
||||
met in your application. This guide focuses on solving the problem using
|
||||
[`Hooks`](../Reference/Hooks.md), [`Decorators`](../Reference/Decorators.md),
|
||||
and [`Plugins`](../Reference/Plugins.md).
|
||||
+ [Detecting When Clients Abort](./Detecting-When-Clients-Abort.md): A
|
||||
+ [Detecting When Clients Abort](./Detecting-When-Clients-Abort.md): A
|
||||
practical guide on detecting if and when a client aborts a request.
|
||||
+ [Ecosystem](./Ecosystem.md): Lists all core plugins and many known community
|
||||
plugins.
|
||||
+ [Fluent Schema](./Fluent-Schema.md): Shows how writing JSON Schema can be
|
||||
+ [Fluent Schema](./Fluent-Schema.md): Shows how JSON Schema can be
|
||||
written with a fluent API and used in Fastify.
|
||||
+ [Getting Started](./Getting-Started.md): Introduction tutorial for Fastify.
|
||||
This is where beginners should start.
|
||||
|
||||
27
backend/node_modules/fastify/docs/Guides/Migration-Guide-V4.md
generated
vendored
27
backend/node_modules/fastify/docs/Guides/Migration-Guide-V4.md
generated
vendored
@@ -9,13 +9,13 @@ work after upgrading.
|
||||
## Codemods
|
||||
### Fastify v4 Codemods
|
||||
|
||||
To help with the upgrade, we’ve worked with the team at
|
||||
To help with the upgrade, we’ve worked with the team at
|
||||
[Codemod](https://github.com/codemod-com/codemod) to
|
||||
publish codemods that will automatically update your code to many of
|
||||
publish codemods that will automatically update your code to many of
|
||||
the new APIs and patterns in Fastify v4.
|
||||
|
||||
Run the following
|
||||
[migration recipe](https://go.codemod.com/fastify-4-migration-recipe) to
|
||||
Run the following
|
||||
[migration recipe](https://go.codemod.com/fastify-4-migration-recipe) to
|
||||
automatically update your code to Fastify v4:
|
||||
|
||||
```
|
||||
@@ -30,7 +30,7 @@ This will run the following codemods:
|
||||
- [`fastify/4/await-register-calls`](https://go.codemod.com/fastify-4-await-register-calls)
|
||||
|
||||
Each of these codemods automates the changes listed in the v4 migration guide.
|
||||
For a complete list of available Fastify codemods and further details,
|
||||
For a complete list of available Fastify codemods and further details,
|
||||
see [Codemod Registry](https://go.codemod.com/fastify).
|
||||
|
||||
|
||||
@@ -52,14 +52,14 @@ fastify.register(async fastify => {
|
||||
console.log(err.message) // 'kaboom'
|
||||
throw new Error('caught')
|
||||
})
|
||||
|
||||
|
||||
fastify.get('/encapsulated', async () => {
|
||||
throw new Error('kaboom')
|
||||
})
|
||||
})
|
||||
|
||||
fastify.setErrorHandler(async err => {
|
||||
console.log(err.message) // 'caught'
|
||||
console.log(err.message) // 'caught'
|
||||
throw new Error('wrapped')
|
||||
})
|
||||
|
||||
@@ -67,10 +67,10 @@ const res = await fastify.inject('/encapsulated')
|
||||
console.log(res.json().message) // 'wrapped'
|
||||
```
|
||||
|
||||
>The root error handler is Fastify’s generic error handler.
|
||||
>This error handler will use the headers and status code in the Error object,
|
||||
>The root error handler is Fastify’s generic error handler.
|
||||
>This error handler will use the headers and status code in the Error object,
|
||||
>if they exist. **The headers and status code will not be automatically set if
|
||||
>a custom error handler is provided**.
|
||||
>a custom error handler is provided**.
|
||||
|
||||
### Removed `app.use()` ([#3506](https://github.com/fastify/fastify/pull/3506))
|
||||
|
||||
@@ -109,7 +109,8 @@ argument from your router handler.
|
||||
### `exposeHeadRoutes` true by default
|
||||
|
||||
Starting with v4, every `GET` route will create a sibling `HEAD` route.
|
||||
You can revert this behavior by setting `exposeHeadRoutes: false` in the server options.
|
||||
You can revert this behavior by setting `exposeHeadRoutes: false` in the server
|
||||
options.
|
||||
|
||||
### Synchronous route definitions ([#2954](https://github.com/fastify/fastify/pull/2954))
|
||||
|
||||
@@ -210,7 +211,7 @@ fastify.get('/posts/:id?', (request, reply) => {
|
||||
The [variadic signature](https://en.wikipedia.org/wiki/Variadic_function) of the
|
||||
`fastify.listen()` method is now deprecated.
|
||||
|
||||
Prior to this release, the following invocations of this method were valid:
|
||||
Before this release, the following invocations of this method were valid:
|
||||
|
||||
- `fastify.listen(8000)`
|
||||
- `fastify.listen(8000, ‘127.0.0.1’)`
|
||||
@@ -242,7 +243,7 @@ As such, schemas like below will need to be changed from:
|
||||
properties: {
|
||||
api_key: { type: 'string' },
|
||||
image: { type: ['object', 'array'] }
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
727
backend/node_modules/fastify/docs/Guides/Migration-Guide-V5.md
generated
vendored
Normal file
727
backend/node_modules/fastify/docs/Guides/Migration-Guide-V5.md
generated
vendored
Normal file
@@ -0,0 +1,727 @@
|
||||
# V5 Migration Guide
|
||||
|
||||
This guide is intended to help with migration from Fastify v4 to v5.
|
||||
|
||||
Before migrating to v5, please ensure that you have fixed all deprecation
|
||||
warnings from v4. All v4 deprecations have been removed and will no longer
|
||||
work after upgrading.
|
||||
|
||||
## Long Term Support Cycle
|
||||
|
||||
Fastify v5 will only support Node.js v20+. If you are using an older version of
|
||||
Node.js, you will need to upgrade to a newer version to use Fastify v5.
|
||||
|
||||
Fastify v4 is still supported until June 30, 2025. If you are unable to upgrade,
|
||||
you should consider buying an end-of-life support plan from HeroDevs.
|
||||
|
||||
### Why Node.js v20?
|
||||
|
||||
Fastify v5 will only support Node.js v20+ because it has significant differences
|
||||
compared to v18, such as
|
||||
better support for `node:test`. This allows us to provide a better developer
|
||||
experience and streamline maintenance.
|
||||
|
||||
Node.js v18 will exit Long Term Support on April 30, 2025, so you should be planning
|
||||
to upgrade to v20 anyway.
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
### Full JSON Schema is now required for `querystring`, `params` and `body` and response schemas
|
||||
|
||||
Starting with v5, Fastify will require a full JSON schema for the `querystring`,
|
||||
`params` and `body` schema. Note that the `jsonShortHand` option has been
|
||||
removed as well.
|
||||
|
||||
If the default JSON Schema validator is used, you will need
|
||||
to provide a full JSON schema for the
|
||||
`querystring`, `params`, `body`, and `response` schemas,
|
||||
including the `type` property.
|
||||
|
||||
```js
|
||||
// v4
|
||||
fastify.get('/route', {
|
||||
schema: {
|
||||
querystring: {
|
||||
name: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}, (req, reply) => {
|
||||
reply.send({ hello: req.query.name });
|
||||
});
|
||||
```
|
||||
|
||||
```js
|
||||
// v5
|
||||
fastify.get('/route', {
|
||||
schema: {
|
||||
querystring: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' }
|
||||
},
|
||||
required: ['name']
|
||||
}
|
||||
}
|
||||
}, (req, reply) => {
|
||||
reply.send({ hello: req.query.name });
|
||||
});
|
||||
```
|
||||
|
||||
See [#5586](https://github.com/fastify/fastify/pull/5586) for more details
|
||||
|
||||
Note that it's still possible to override the JSON Schema validator to
|
||||
use a different format, such as Zod. This change simplifies that as well.
|
||||
|
||||
This change helps with integration of other tools, such as
|
||||
[`@fastify/swagger`](https://github.com/fastify/fastify-swagger).
|
||||
|
||||
### New logger constructor signature
|
||||
|
||||
In Fastify v4, Fastify accepted the options to build a pino
|
||||
logger in the `logger` option, as well as a custom logger instance.
|
||||
This was the source of significant confusion.
|
||||
|
||||
As a result, the `logger` option will not accept a custom logger anymore in v5.
|
||||
To use a custom logger, you should use the `loggerInstance` option instead:
|
||||
|
||||
```js
|
||||
// v4
|
||||
const logger = require('pino')();
|
||||
const fastify = require('fastify')({
|
||||
logger
|
||||
});
|
||||
```
|
||||
|
||||
```js
|
||||
// v5
|
||||
const loggerInstance = require('pino')();
|
||||
const fastify = require('fastify')({
|
||||
loggerInstance
|
||||
});
|
||||
```
|
||||
|
||||
### `useSemicolonDelimiter` false by default
|
||||
|
||||
Starting with v5, Fastify instances will no longer default to supporting the use
|
||||
of semicolon delimiters in the query string as they did in v4.
|
||||
This is due to it being non-standard
|
||||
behavior and not adhering to [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986#section-3.4).
|
||||
|
||||
If you still wish to use semicolons as delimiters, you can do so by
|
||||
setting `useSemicolonDelimiter: true` in the server configuration.
|
||||
|
||||
```js
|
||||
const fastify = require('fastify')({
|
||||
useSemicolonDelimiter: true
|
||||
});
|
||||
```
|
||||
|
||||
### The parameters object no longer has a prototype
|
||||
|
||||
In v4, the `parameters` object had a prototype. This is no longer the case in v5.
|
||||
This means that you can no longer access properties inherited from `Object` on
|
||||
the `parameters` object, such as `toString` or `hasOwnProperty`.
|
||||
|
||||
```js
|
||||
// v4
|
||||
fastify.get('/route/:name', (req, reply) => {
|
||||
console.log(req.params.hasOwnProperty('name')); // true
|
||||
return { hello: req.params.name };
|
||||
});
|
||||
```
|
||||
|
||||
```js
|
||||
// v5
|
||||
fastify.get('/route/:name', (req, reply) => {
|
||||
console.log(Object.hasOwn(req.params, 'name')); // true
|
||||
return { hello: req.params.name };
|
||||
});
|
||||
```
|
||||
|
||||
This increases the security of the application by hardening against prototype
|
||||
pollution attacks.
|
||||
|
||||
### Type Providers now differentiate between validator and serializer schemas
|
||||
|
||||
In v4, the type providers had the same types for both validation and serialization.
|
||||
In v5, the type providers have been split into two separate types: `ValidatorSchema`
|
||||
and `SerializerSchema`.
|
||||
|
||||
[`@fastify/type-provider-json-schema-to-ts`](https://github.com/fastify/fastify-type-provider-json-schema-to-ts)
|
||||
and
|
||||
[`@fastify/type-provider-typebox`](https://github.com/fastify/fastify-type-provider-typebox)
|
||||
have already been updated: upgrade to the latest version to get the new types.
|
||||
If you are using a custom type provider, you will need to modify it like
|
||||
the following:
|
||||
|
||||
```
|
||||
--- a/index.ts
|
||||
+++ b/index.ts
|
||||
@@ -11,7 +11,8 @@ import {
|
||||
import { FromSchema, FromSchemaDefaultOptions, FromSchemaOptions, JSONSchema } from 'json-schema-to-ts'
|
||||
|
||||
export interface JsonSchemaToTsProvider<
|
||||
Options extends FromSchemaOptions = FromSchemaDefaultOptions
|
||||
> extends FastifyTypeProvider {
|
||||
- output: this['input'] extends JSONSchema ? FromSchema<this['input'], Options> : unknown;
|
||||
+ validator: this['schema'] extends JSONSchema ? FromSchema<this['schema'], Options> : unknown;
|
||||
+ serializer: this['schema'] extends JSONSchema ? FromSchema<this['schema'], Options> : unknown;
|
||||
}
|
||||
```
|
||||
|
||||
### Changes to the .listen() method
|
||||
|
||||
The variadic argument signature of the `.listen()` method has been removed.
|
||||
This means that you can no longer call `.listen()` with a variable number of arguments.
|
||||
|
||||
```js
|
||||
// v4
|
||||
fastify.listen(8000)
|
||||
```
|
||||
|
||||
Will become:
|
||||
|
||||
```js
|
||||
// v5
|
||||
fastify.listen({ port: 8000 })
|
||||
```
|
||||
|
||||
This was already deprecated in v4 as `FSTDEP011`, so you should have already updated
|
||||
your code to use the new signature.
|
||||
|
||||
### Direct return of trailers has been removed
|
||||
|
||||
In v4, you could directly return trailers from a handler.
|
||||
This is no longer possible in v5.
|
||||
|
||||
```js
|
||||
// v4
|
||||
fastify.get('/route', (req, reply) => {
|
||||
reply.trailer('ETag', function (reply, payload) {
|
||||
return 'custom-etag'
|
||||
})
|
||||
reply.send('')
|
||||
});
|
||||
```
|
||||
|
||||
```js
|
||||
// v5
|
||||
fastify.get('/route', (req, reply) => {
|
||||
reply.trailer('ETag', async function (reply, payload) {
|
||||
return 'custom-etag'
|
||||
})
|
||||
reply.send('')
|
||||
});
|
||||
```
|
||||
|
||||
A callback could also be used.
|
||||
This was already deprecated in v4 as `FSTDEP013`,
|
||||
so you should have already updated your code to use the new signature.
|
||||
|
||||
### Streamlined access to route definition
|
||||
|
||||
All deprecated properties relating to accessing the route definition have been removed
|
||||
and are now accessed via `request.routeOptions`.
|
||||
|
||||
| Code | Description | How to solve | Discussion |
|
||||
| ---- | ----------- | ------------ | ---------- |
|
||||
| FSTDEP012 | You are trying to access the deprecated `request.context` property. | Use `request.routeOptions.config` or `request.routeOptions.schema`. | [#4216](https://github.com/fastify/fastify/pull/4216) [#5084](https://github.com/fastify/fastify/pull/5084) |
|
||||
| FSTDEP015 | You are accessing the deprecated `request.routeSchema` property. | Use `request.routeOptions.schema`. | [#4470](https://github.com/fastify/fastify/pull/4470) |
|
||||
| FSTDEP016 | You are accessing the deprecated `request.routeConfig` property. | Use `request.routeOptions.config`. | [#4470](https://github.com/fastify/fastify/pull/4470) |
|
||||
| FSTDEP017 | You are accessing the deprecated `request.routerPath` property. | Use `request.routeOptions.url`. | [#4470](https://github.com/fastify/fastify/pull/4470) |
|
||||
| FSTDEP018 | You are accessing the deprecated `request.routerMethod` property. | Use `request.routeOptions.method`. | [#4470](https://github.com/fastify/fastify/pull/4470) |
|
||||
| FSTDEP019 | You are accessing the deprecated `reply.context` property. | Use `reply.routeOptions.config` or `reply.routeOptions.schema`. | [#5032](https://github.com/fastify/fastify/pull/5032) [#5084](https://github.com/fastify/fastify/pull/5084) |
|
||||
|
||||
See [#5616](https://github.com/fastify/fastify/pull/5616) for more information.
|
||||
|
||||
### `reply.redirect()` has a new signature
|
||||
|
||||
The `reply.redirect()` method has a new signature:
|
||||
`reply.redirect(url: string, code?: number)`.
|
||||
|
||||
```js
|
||||
// v4
|
||||
reply.redirect(301, '/new-route')
|
||||
```
|
||||
|
||||
Change it to:
|
||||
|
||||
```js
|
||||
// v5
|
||||
reply.redirect('/new-route', 301)
|
||||
```
|
||||
|
||||
This was already deprecated in v4 as `FSTDEP021`, so you should have already
|
||||
updated your code to use the new signature.
|
||||
|
||||
|
||||
### Modifying `reply.sent` is now forbidden
|
||||
|
||||
In v4, you could modify the `reply.sent` property to prevent the response from
|
||||
being sent.
|
||||
This is no longer possible in v5, use `reply.hijack()` instead.
|
||||
|
||||
```js
|
||||
// v4
|
||||
fastify.get('/route', (req, reply) => {
|
||||
reply.sent = true;
|
||||
reply.raw.end('hello');
|
||||
});
|
||||
```
|
||||
|
||||
Change it to:
|
||||
|
||||
```js
|
||||
// v5
|
||||
fastify.get('/route', (req, reply) => {
|
||||
reply.hijack();
|
||||
reply.raw.end('hello');
|
||||
});
|
||||
```
|
||||
|
||||
This was already deprecated in v4 as `FSTDEP010`, so you should have already
|
||||
updated your code to use the new signature.
|
||||
|
||||
### Constraints for route versioning signature changes
|
||||
|
||||
We changed the signature for route versioning constraints.
|
||||
The `version` and `versioning` options have been removed and you should
|
||||
use the `constraints` option instead.
|
||||
|
||||
| Code | Description | How to solve | Discussion |
|
||||
| ---- | ----------- | ------------ | ---------- |
|
||||
| FSTDEP008 | You are using route constraints via the route `{version: "..."}` option. | Use `{constraints: {version: "..."}}` option. | [#2682](https://github.com/fastify/fastify/pull/2682) |
|
||||
| FSTDEP009 | You are using a custom route versioning strategy via the server `{versioning: "..."}` option. | Use `{constraints: {version: "..."}}` option. | [#2682](https://github.com/fastify/fastify/pull/2682) |
|
||||
|
||||
### `HEAD` routes requires to register before `GET` when `exposeHeadRoutes: true`
|
||||
|
||||
We have a more strict requirement for custom `HEAD` route when
|
||||
`exposeHeadRoutes: true`.
|
||||
|
||||
When you provides a custom `HEAD` route, you must either explicitly
|
||||
set `exposeHeadRoutes` to `false`
|
||||
|
||||
```js
|
||||
// v4
|
||||
fastify.get('/route', {
|
||||
|
||||
}, (req, reply) => {
|
||||
reply.send({ hello: 'world' });
|
||||
});
|
||||
|
||||
fastify.head('/route', (req, reply) => {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
```js
|
||||
// v5
|
||||
fastify.get('/route', {
|
||||
exposeHeadRoutes: false
|
||||
}, (req, reply) => {
|
||||
reply.send({ hello: 'world' });
|
||||
});
|
||||
|
||||
fastify.head('/route', (req, reply) => {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
or place the `HEAD` route before `GET`.
|
||||
|
||||
```js
|
||||
// v5
|
||||
fastify.head('/route', (req, reply) => {
|
||||
// ...
|
||||
});
|
||||
|
||||
fastify.get('/route', {
|
||||
|
||||
}, (req, reply) => {
|
||||
reply.send({ hello: 'world' });
|
||||
});
|
||||
```
|
||||
|
||||
This was changed in [#2700](https://github.com/fastify/fastify/pull/2700),
|
||||
and the old behavior was deprecated in v4 as `FSTDEP007`.
|
||||
|
||||
### Removed `request.connection`
|
||||
|
||||
The `request.connection` property has been removed in v5.
|
||||
You should use `request.socket` instead.
|
||||
|
||||
```js
|
||||
// v4
|
||||
fastify.get('/route', (req, reply) => {
|
||||
console.log(req.connection.remoteAddress);
|
||||
return { hello: 'world' };
|
||||
});
|
||||
```
|
||||
|
||||
```js
|
||||
// v5
|
||||
fastify.get('/route', (req, reply) => {
|
||||
console.log(req.socket.remoteAddress);
|
||||
return { hello: 'world' };
|
||||
});
|
||||
```
|
||||
|
||||
This was already deprecated in v4 as `FSTDEP05`, so you should
|
||||
have already updated your code to use the new signature.
|
||||
|
||||
### `reply.getResponseTime()` has been removed, use `reply.elapsedTime` instead
|
||||
|
||||
The `reply.getResponseTime()` method has been removed in v5.
|
||||
You should use `reply.elapsedTime` instead.
|
||||
|
||||
```js
|
||||
// v4
|
||||
fastify.get('/route', (req, reply) => {
|
||||
console.log(reply.getResponseTime());
|
||||
return { hello: 'world' };
|
||||
});
|
||||
```
|
||||
|
||||
```js
|
||||
// v5
|
||||
fastify.get('/route', (req, reply) => {
|
||||
console.log(reply.elapsedTime);
|
||||
return { hello: 'world' };
|
||||
});
|
||||
```
|
||||
|
||||
This was already deprecated in v4 as `FSTDEP20`, so you should have already
|
||||
updated your code to use the new signature.
|
||||
|
||||
### `fastify.hasRoute()` now matches the behavior of `find-my-way`
|
||||
|
||||
The `fastify.hasRoute()` method now matches the behavior of `find-my-way`
|
||||
and requires the route definition to be passed as it is defined in the route.
|
||||
|
||||
```js
|
||||
// v4
|
||||
fastify.get('/example/:file(^\\d+).png', function (request, reply) { })
|
||||
|
||||
console.log(fastify.hasRoute({
|
||||
method: 'GET',
|
||||
url: '/example/12345.png'
|
||||
)); // true
|
||||
```
|
||||
|
||||
```js
|
||||
// v5
|
||||
|
||||
fastify.get('/example/:file(^\\d+).png', function (request, reply) { })
|
||||
|
||||
console.log(fastify.hasRoute({
|
||||
method: 'GET',
|
||||
url: '/example/:file(^\\d+).png'
|
||||
)); // true
|
||||
```
|
||||
|
||||
### Removal of some non-standard HTTP methods
|
||||
|
||||
We have removed the following HTTP methods from Fastify:
|
||||
- `PROPFIND`
|
||||
- `PROPPATCH`
|
||||
- `MKCOL`
|
||||
- `COPY`
|
||||
- `MOVE`
|
||||
- `LOCK`
|
||||
- `UNLOCK`
|
||||
- `TRACE`
|
||||
- `SEARCH`
|
||||
|
||||
It's now possible to add them back using the `addHttpMethod` method.
|
||||
|
||||
```js
|
||||
const fastify = Fastify()
|
||||
|
||||
// add a new http method on top of the default ones:
|
||||
fastify.addHttpMethod('REBIND')
|
||||
|
||||
// add a new HTTP method that accepts a body:
|
||||
fastify.addHttpMethod('REBIND', { hasBody: true })
|
||||
|
||||
// reads the HTTP methods list:
|
||||
fastify.supportedMethods // returns a string array
|
||||
```
|
||||
|
||||
See [#5567](https://github.com/fastify/fastify/pull/5567) for more
|
||||
information.
|
||||
|
||||
### Removed support from reference types in decorators
|
||||
|
||||
Decorating Request/Reply with a reference type (`Array`, `Object`)
|
||||
is now prohibited as this reference is shared amongst all requests.
|
||||
|
||||
```js
|
||||
// v4
|
||||
fastify.decorateRequest('myObject', { hello: 'world' });
|
||||
```
|
||||
|
||||
```js
|
||||
// v5
|
||||
fastify.decorateRequest('myObject');
|
||||
fastify.addHook('onRequest', async (req, reply) => {
|
||||
req.myObject = { hello: 'world' };
|
||||
});
|
||||
```
|
||||
|
||||
or turn it into a function
|
||||
|
||||
```js
|
||||
// v5
|
||||
fastify.decorateRequest('myObject', () => ({ hello: 'world' }));
|
||||
```
|
||||
|
||||
or as a getter
|
||||
|
||||
```js
|
||||
// v5
|
||||
fastify.decorateRequest('myObject', {
|
||||
getter () {
|
||||
return { hello: 'world' }
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
See [#5462](https://github.com/fastify/fastify/pull/5462) for more information.
|
||||
|
||||
### Remove support for DELETE with a `Content-Type: application/json` header and an empty body
|
||||
|
||||
In v4, Fastify allowed `DELETE` requests with a `Content-Type: application/json`
|
||||
header and an empty body was accepted.
|
||||
This is no longer allowed in v5.
|
||||
|
||||
See [#5419](https://github.com/fastify/fastify/pull/5419) for more information.
|
||||
|
||||
### Plugins cannot mix callback/promise API anymore
|
||||
|
||||
In v4, plugins could mix the callback and promise API, leading to unexpected behavior.
|
||||
This is no longer allowed in v5.
|
||||
|
||||
```js
|
||||
// v4
|
||||
fastify.register(async function (instance, opts, done) {
|
||||
done();
|
||||
});
|
||||
```
|
||||
|
||||
```js
|
||||
// v5
|
||||
fastify.register(async function (instance, opts) {
|
||||
return;
|
||||
});
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```js
|
||||
// v5
|
||||
fastify.register(function (instance, opts, done) {
|
||||
done();
|
||||
});
|
||||
```
|
||||
|
||||
### Requests now have `host`, `hostname`, and `port`, and `hostname` no longer includes the port number
|
||||
|
||||
In Fastify v4, `req.hostname` would include both the hostname and the
|
||||
server’s port, so locally it might have the value `localhost:1234`.
|
||||
With v5, we aligned to the Node.js URL object and now include `host`, `hostname`,
|
||||
and `port` properties. `req.host` has the same value as `req.hostname` did in v4,
|
||||
while `req.hostname` includes the hostname _without_ a port if a port is present,
|
||||
and `req.port` contains just the port number.
|
||||
See [#4766](https://github.com/fastify/fastify/pull/4766)
|
||||
and [#4682](https://github.com/fastify/fastify/issues/4682) for more information.
|
||||
|
||||
### Removes `getDefaultRoute` and `setDefaultRoute` methods
|
||||
|
||||
The `getDefaultRoute` and `setDefaultRoute` methods have been removed in v5.
|
||||
|
||||
See [#4485](https://github.com/fastify/fastify/pull/4485)
|
||||
and [#4480](https://github.com/fastify/fastify/pull/4485)
|
||||
for more information.
|
||||
This was already deprecated in v4 as `FSTDEP014`,
|
||||
so you should have already updated your code.
|
||||
|
||||
### `time` and `date-time` formats enforce timezone
|
||||
|
||||
The updated AJV compiler updates `ajv-formats` which now
|
||||
enforce the use of timezone in `time` and `date-time` format.
|
||||
A workaround is to use `iso-time` and `iso-date-time` formats
|
||||
which support an optional timezone for backwards compatibility.
|
||||
See the
|
||||
[full discussion](https://github.com/fastify/fluent-json-schema/issues/267).
|
||||
|
||||
## New Features
|
||||
|
||||
### Diagnostic Channel support
|
||||
|
||||
Fastify v5 now supports the [Diagnostics Channel](https://nodejs.org/api/diagnostics_channel.html)
|
||||
API natively
|
||||
and provides a way to trace the lifecycle of a request.
|
||||
|
||||
```js
|
||||
'use strict'
|
||||
|
||||
const diagnostics = require('node:diagnostics_channel')
|
||||
const Fastify = require('fastify')
|
||||
|
||||
diagnostics.subscribe('tracing:fastify.request.handler:start', (msg) => {
|
||||
console.log(msg.route.url) // '/:id'
|
||||
console.log(msg.route.method) // 'GET'
|
||||
})
|
||||
|
||||
diagnostics.subscribe('tracing:fastify.request.handler:end', (msg) => {
|
||||
// msg is the same as the one emitted by the 'tracing:fastify.request.handler:start' channel
|
||||
console.log(msg)
|
||||
})
|
||||
|
||||
diagnostics.subscribe('tracing:fastify.request.handler:error', (msg) => {
|
||||
// in case of error
|
||||
})
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/:id',
|
||||
handler: function (req, reply) {
|
||||
return { hello: 'world' }
|
||||
}
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, async function () {
|
||||
const result = await fetch(fastify.listeningOrigin + '/7')
|
||||
|
||||
t.assert.ok(result.ok)
|
||||
t.assert.strictEqual(response.status, 200)
|
||||
t.assert.deepStrictEqual(await result.json(), { hello: 'world' })
|
||||
})
|
||||
```
|
||||
|
||||
See the [documentation](https://github.com/fastify/fastify/blob/main/docs/Reference/Hooks.md#diagnostics-channel-hooks)
|
||||
and [#5252](https://github.com/fastify/fastify/pull/5252) for additional details.
|
||||
|
||||
## Contributors
|
||||
|
||||
The complete list of contributors, across all of the core
|
||||
Fastify packages, is provided below. Please consider
|
||||
contributing to those that are capable of accepting sponsorships.
|
||||
|
||||
| Contributor | Sponsor Link | Packages |
|
||||
| --- | --- | --- |
|
||||
| 10xLaCroixDrinker | [❤️ sponsor](https://github.com/sponsors/10xLaCroixDrinker) | fastify-cli |
|
||||
| Bram-dc | | fastify; fastify-swagger |
|
||||
| BrianValente | | fastify |
|
||||
| BryanAbate | | fastify-cli |
|
||||
| Cadienvan | [❤️ sponsor](https://github.com/sponsors/Cadienvan) | fastify |
|
||||
| Cangit | | fastify |
|
||||
| Cyberlane | | fastify-elasticsearch |
|
||||
| Eomm | [❤️ sponsor](https://github.com/sponsors/Eomm) | ajv-compiler; fastify; fastify-awilix; fastify-diagnostics-channel; fastify-elasticsearch; fastify-hotwire; fastify-mongodb; fastify-nextjs; fastify-swagger-ui; under-pressure |
|
||||
| EstebanDalelR | [❤️ sponsor](https://github.com/sponsors/EstebanDalelR) | fastify-cli |
|
||||
| Fdawgs | [❤️ sponsor](https://github.com/sponsors/Fdawgs) | aws-lambda-fastify; csrf-protection; env-schema; fastify; fastify-accepts; fastify-accepts-serializer; fastify-auth; fastify-awilix; fastify-basic-auth; fastify-bearer-auth; fastify-caching; fastify-circuit-breaker; fastify-cli; fastify-cookie; fastify-cors; fastify-diagnostics-channel; fastify-elasticsearch; fastify-env; fastify-error; fastify-etag; fastify-express; fastify-flash; fastify-formbody; fastify-funky; fastify-helmet; fastify-hotwire; fastify-http-proxy; fastify-jwt; fastify-kafka; fastify-leveldb; fastify-mongodb; fastify-multipart; fastify-mysql; fastify-nextjs; fastify-oauth2; fastify-passport; fastify-plugin; fastify-postgres; fastify-rate-limit; fastify-redis; fastify-reply-from; fastify-request-context; fastify-response-validation; fastify-routes; fastify-routes-stats; fastify-schedule; fastify-secure-session; fastify-sensible; fastify-swagger-ui; fastify-url-data; fastify-websocket; fastify-zipkin; fluent-json-schema; forwarded; middie; point-of-view; process-warning; proxy-addr; safe-regex2; secure-json-parse; under-pressure |
|
||||
| Gehbt | | fastify-secure-session |
|
||||
| Gesma94 | | fastify-routes-stats |
|
||||
| H4ad | [❤️ sponsor](https://github.com/sponsors/H4ad) | aws-lambda-fastify |
|
||||
| JohanManders | | fastify-secure-session |
|
||||
| LiviaMedeiros | | fastify |
|
||||
| Momy93 | | fastify-secure-session |
|
||||
| MunifTanjim | | fastify-swagger-ui |
|
||||
| Nanosync | | fastify-secure-session |
|
||||
| RafaelGSS | [❤️ sponsor](https://github.com/sponsors/RafaelGSS) | fastify; under-pressure |
|
||||
| Rantoledo | | fastify |
|
||||
| SMNBLMRR | | fastify |
|
||||
| SimoneDevkt | | fastify-cli |
|
||||
| Tony133 | | fastify |
|
||||
| Uzlopak | [❤️ sponsor](https://github.com/sponsors/Uzlopak) | fastify; fastify-autoload; fastify-diagnostics-channel; fastify-hotwire; fastify-nextjs; fastify-passport; fastify-plugin; fastify-rate-limit; fastify-routes; fastify-static; fastify-swagger-ui; point-of-view; under-pressure |
|
||||
| Zamiell | | fastify-secure-session |
|
||||
| aadito123 | | fastify |
|
||||
| aaroncadillac | [❤️ sponsor](https://github.com/sponsors/aaroncadillac) | fastify |
|
||||
| aarontravass | | fastify |
|
||||
| acro5piano | [❤️ sponsor](https://github.com/sponsors/acro5piano) | fastify-secure-session |
|
||||
| adamward459 | | fastify-cli |
|
||||
| adrai | [❤️ sponsor](https://github.com/sponsors/adrai) | aws-lambda-fastify |
|
||||
| alenap93 | | fastify |
|
||||
| alexandrucancescu | | fastify-nextjs |
|
||||
| anthonyringoet | | aws-lambda-fastify |
|
||||
| arshcodemod | | fastify |
|
||||
| autopulated | | point-of-view |
|
||||
| barbieri | | fastify |
|
||||
| beyazit | | fastify |
|
||||
| big-kahuna-burger | [❤️ sponsor](https://github.com/sponsors/big-kahuna-burger) | fastify-cli; fastify-compress; fastify-helmet |
|
||||
| bilalshareef | | fastify-routes |
|
||||
| blue86321 | | fastify-swagger-ui |
|
||||
| bodinsamuel | | fastify-rate-limit |
|
||||
| busybox11 | [❤️ sponsor](https://github.com/sponsors/busybox11) | fastify |
|
||||
| climba03003 | | csrf-protection; fastify; fastify-accepts; fastify-accepts-serializer; fastify-auth; fastify-basic-auth; fastify-bearer-auth; fastify-caching; fastify-circuit-breaker; fastify-compress; fastify-cors; fastify-env; fastify-etag; fastify-flash; fastify-formbody; fastify-http-proxy; fastify-mongodb; fastify-swagger-ui; fastify-url-data; fastify-websocket; middie |
|
||||
| dancastillo | [❤️ sponsor](https://github.com/sponsors/dancastillo) | fastify; fastify-basic-auth; fastify-caching; fastify-circuit-breaker; fastify-cors; fastify-helmet; fastify-passport; fastify-response-validation; fastify-routes; fastify-schedule |
|
||||
| danny-andrews | | fastify-kafka |
|
||||
| davidcralph | [❤️ sponsor](https://github.com/sponsors/davidcralph) | csrf-protection |
|
||||
| davideroffo | | under-pressure |
|
||||
| dhensby | | fastify-cli |
|
||||
| dmkng | | fastify |
|
||||
| domdomegg | | fastify |
|
||||
| faustman | | fastify-cli |
|
||||
| floridemai | | fluent-json-schema |
|
||||
| fox1t | | fastify-autoload |
|
||||
| giuliowaitforitdavide | | fastify |
|
||||
| gunters63 | | fastify-reply-from |
|
||||
| gurgunday | | fastify; fastify-circuit-breaker; fastify-cookie; fastify-multipart; fastify-mysql; fastify-rate-limit; fastify-response-validation; fastify-sensible; fastify-swagger-ui; fluent-json-schema; middie; proxy-addr; safe-regex2; secure-json-parse |
|
||||
| ildella | | under-pressure |
|
||||
| james-kaguru | | fastify |
|
||||
| jcbain | | fastify-http-proxy |
|
||||
| jdhollander | | fastify-swagger-ui |
|
||||
| jean-michelet | | fastify; fastify-autoload; fastify-cli; fastify-mysql; fastify-sensible |
|
||||
| johaven | | fastify-multipart |
|
||||
| jordanebelanger | | fastify-plugin |
|
||||
| jscheffner | | fastify |
|
||||
| jsprw | | fastify-secure-session |
|
||||
| jsumners | [❤️ sponsor](https://github.com/sponsors/jsumners) | ajv-compiler; avvio; csrf-protection; env-schema; fast-json-stringify; fastify; fastify-accepts; fastify-accepts-serializer; fastify-auth; fastify-autoload; fastify-awilix; fastify-basic-auth; fastify-bearer-auth; fastify-caching; fastify-circuit-breaker; fastify-compress; fastify-cookie; fastify-cors; fastify-env; fastify-error; fastify-etag; fastify-express; fastify-flash; fastify-formbody; fastify-funky; fastify-helmet; fastify-http-proxy; fastify-jwt; fastify-kafka; fastify-leveldb; fastify-multipart; fastify-mysql; fastify-oauth2; fastify-plugin; fastify-postgres; fastify-redis; fastify-reply-from; fastify-request-context; fastify-response-validation; fastify-routes; fastify-routes-stats; fastify-schedule; fastify-secure-session; fastify-sensible; fastify-static; fastify-swagger; fastify-swagger-ui; fastify-url-data; fastify-websocket; fastify-zipkin; fluent-json-schema; forwarded; light-my-request; middie; process-warning; proxy-addr; safe-regex2; secure-json-parse; under-pressure |
|
||||
| karankraina | | under-pressure |
|
||||
| kerolloz | [❤️ sponsor](https://github.com/sponsors/kerolloz) | fastify-jwt |
|
||||
| kibertoad | | fastify-rate-limit |
|
||||
| kukidon-dev | | fastify-passport |
|
||||
| kunal097 | | fastify |
|
||||
| lamweili | | fastify-sensible |
|
||||
| lemonclown | | fastify-mongodb |
|
||||
| liuhanqu | | fastify |
|
||||
| matthyk | | fastify-plugin |
|
||||
| mch-dsk | | fastify |
|
||||
| mcollina | [❤️ sponsor](https://github.com/sponsors/mcollina) | ajv-compiler; avvio; csrf-protection; fastify; fastify-accepts; fastify-accepts-serializer; fastify-auth; fastify-autoload; fastify-awilix; fastify-basic-auth; fastify-bearer-auth; fastify-caching; fastify-circuit-breaker; fastify-cli; fastify-compress; fastify-cookie; fastify-cors; fastify-diagnostics-channel; fastify-elasticsearch; fastify-env; fastify-etag; fastify-express; fastify-flash; fastify-formbody; fastify-funky; fastify-helmet; fastify-http-proxy; fastify-jwt; fastify-kafka; fastify-leveldb; fastify-multipart; fastify-mysql; fastify-oauth2; fastify-passport; fastify-plugin; fastify-postgres; fastify-rate-limit; fastify-redis; fastify-reply-from; fastify-request-context; fastify-response-validation; fastify-routes; fastify-routes-stats; fastify-schedule; fastify-secure-session; fastify-static; fastify-swagger; fastify-swagger-ui; fastify-url-data; fastify-websocket; fastify-zipkin; fluent-json-schema; light-my-request; middie; point-of-view; proxy-addr; secure-json-parse; under-pressure |
|
||||
| melroy89 | [❤️ sponsor](https://github.com/sponsors/melroy89) | under-pressure |
|
||||
| metcoder95 | [❤️ sponsor](https://github.com/sponsors/metcoder95) | fastify-elasticsearch |
|
||||
| mhamann | | fastify-cli |
|
||||
| mihaur | | fastify-elasticsearch |
|
||||
| mikesamm | | fastify |
|
||||
| mikhael-abdallah | | secure-json-parse |
|
||||
| miquelfire | [❤️ sponsor](https://github.com/sponsors/miquelfire) | fastify-routes |
|
||||
| miraries | | fastify-swagger-ui |
|
||||
| mohab-sameh | | fastify |
|
||||
| monish001 | | fastify |
|
||||
| moradebianchetti81 | | fastify |
|
||||
| mouhannad-sh | | aws-lambda-fastify |
|
||||
| multivoltage | | point-of-view |
|
||||
| muya | [❤️ sponsor](https://github.com/sponsors/muya) | under-pressure |
|
||||
| mweberxyz | | point-of-view |
|
||||
| nflaig | | fastify |
|
||||
| nickfla1 | | avvio |
|
||||
| o-az | | process-warning |
|
||||
| ojeytonwilliams | | csrf-protection |
|
||||
| onosendi | | fastify-formbody |
|
||||
| philippviereck | | fastify |
|
||||
| pip77 | | fastify-mongodb |
|
||||
| puskin94 | | fastify |
|
||||
| remidewitte | | fastify |
|
||||
| rozzilla | | fastify |
|
||||
| samialdury | | fastify-cli |
|
||||
| sknetl | | fastify-cors |
|
||||
| sourcecodeit | | fastify |
|
||||
| synapse | | env-schema |
|
||||
| timursaurus | | secure-json-parse |
|
||||
| tlhunter | | fastify |
|
||||
| tlund101 | | fastify-rate-limit |
|
||||
| ttshivers | | fastify-http-proxy |
|
||||
| voxpelli | [❤️ sponsor](https://github.com/sponsors/voxpelli) | fastify |
|
||||
| weixinwu | | fastify-cli |
|
||||
| zetaraku | | fastify-cli |
|
||||
14
backend/node_modules/fastify/docs/Guides/Plugins-Guide.md
generated
vendored
14
backend/node_modules/fastify/docs/Guides/Plugins-Guide.md
generated
vendored
@@ -71,8 +71,8 @@ order of plugins. *How?* Glad you asked, check out
|
||||
[`avvio`](https://github.com/mcollina/avvio)! Fastify starts loading the plugin
|
||||
__after__ `.listen()`, `.inject()` or `.ready()` are called.
|
||||
|
||||
Inside a plugin you can do whatever you want, register routes, utilities (we
|
||||
will see this in a moment) and do nested registers, just remember to call `done`
|
||||
Inside a plugin you can do whatever you want, register routes and utilities (we
|
||||
will see this in a moment), and do nested registers, just remember to call `done`
|
||||
when everything is set up!
|
||||
```js
|
||||
module.exports = function (fastify, options, done) {
|
||||
@@ -117,7 +117,7 @@ Now you can access your utility just by calling `fastify.util` whenever you need
|
||||
it - even inside your test.
|
||||
|
||||
And here starts the magic; do you remember how just now we were talking about
|
||||
encapsulation? Well, using `register` and `decorate` in conjunction enable
|
||||
encapsulation? Well, using `register` and `decorate` in conjunction enables
|
||||
exactly that, let me show you an example to clarify this:
|
||||
```js
|
||||
fastify.register((instance, opts, done) => {
|
||||
@@ -137,7 +137,7 @@ Inside the second register call `instance.util` will throw an error because
|
||||
`util` exists only inside the first register context.
|
||||
|
||||
Let's step back for a moment and dig deeper into this: every time you use the
|
||||
`register` API, a new context is created which avoids the negative situations
|
||||
`register` API, a new context is created that avoids the negative situations
|
||||
mentioned above.
|
||||
|
||||
Do note that encapsulation applies to the ancestors and siblings, but not the
|
||||
@@ -202,7 +202,7 @@ a utility that also needs access to the `request` and `reply` instance,
|
||||
a function that is defined using the `function` keyword is needed instead
|
||||
of an *arrow function expression*.
|
||||
|
||||
In the same way you can do this for the `request` object:
|
||||
You can do the same for the `request` object:
|
||||
```js
|
||||
fastify.decorate('getHeader', (req, header) => {
|
||||
return req.headers[header]
|
||||
@@ -316,7 +316,7 @@ based on a [route config option](../Reference/Routes.md#routes-options):
|
||||
```js
|
||||
fastify.register((instance, opts, done) => {
|
||||
instance.decorate('util', (request, key, value) => { request[key] = value })
|
||||
|
||||
|
||||
function handler(request, reply, done) {
|
||||
instance.util(request, 'timestamp', new Date())
|
||||
done()
|
||||
@@ -395,7 +395,7 @@ As we mentioned earlier, Fastify starts loading its plugins __after__
|
||||
have been declared. This means that, even though the plugin may inject variables
|
||||
to the external Fastify instance via [`decorate`](../Reference/Decorators.md),
|
||||
the decorated variables will not be accessible before calling `.listen()`,
|
||||
`.inject()` or `.ready()`.
|
||||
`.inject()`, or `.ready()`.
|
||||
|
||||
In case you rely on a variable injected by a preceding plugin and want to pass
|
||||
that in the `options` argument of `register`, you can do so by using a function
|
||||
|
||||
6
backend/node_modules/fastify/docs/Guides/Prototype-Poisoning.md
generated
vendored
6
backend/node_modules/fastify/docs/Guides/Prototype-Poisoning.md
generated
vendored
@@ -8,7 +8,7 @@
|
||||
<a id="pp"></a>
|
||||
|
||||
Based on the article by Eran Hammer,the issue is created by a web security bug.
|
||||
It is also a perfect illustration of the efforts required to maintain
|
||||
It is also a perfect illustration of the efforts required to maintain
|
||||
open-source software and the limitations of existing communication channels.
|
||||
|
||||
But first, if we use a JavaScript framework to process incoming JSON data, take
|
||||
@@ -16,7 +16,7 @@ a moment to read up on [Prototype Poisoning](https://medium.com/intrinsic/javasc
|
||||
in general, and the specific
|
||||
[technical details](https://github.com/hapijs/hapi/issues/3916) of this issue.
|
||||
This could be a critical issue so, we might need to verify your own code first.
|
||||
It focuses on specific framework however, any solution that uses `JSON.parse()`
|
||||
It focuses on specific framework however, any solution that uses `JSON.parse()`
|
||||
to process external data is potentially at risk.
|
||||
|
||||
### BOOM
|
||||
@@ -42,7 +42,7 @@ defect a validation library can have.
|
||||
|
||||
To understand this, we need to understand how JavaScript works a bit.
|
||||
Every object in JavaScript can have a prototype. It is a set of methods and
|
||||
properties it "inherits" from another object. I have put inherits in quotes
|
||||
properties it "inherits" from another object. I have put inherits in quotes
|
||||
because JavaScript isn't really an object-oriented language. It is a prototype-
|
||||
based object-oriented language.
|
||||
|
||||
|
||||
34
backend/node_modules/fastify/docs/Guides/Recommendations.md
generated
vendored
34
backend/node_modules/fastify/docs/Guides/Recommendations.md
generated
vendored
@@ -212,17 +212,19 @@ server {
|
||||
# server group via port 3000.
|
||||
server {
|
||||
# This listen directive asks NGINX to accept requests
|
||||
# coming to any address, port 443, with SSL, and HTTP/2
|
||||
# if possible.
|
||||
listen 443 ssl http2 default_server;
|
||||
listen [::]:443 ssl http2 default_server;
|
||||
# coming to any address, port 443, with SSL.
|
||||
listen 443 ssl default_server;
|
||||
listen [::]:443 ssl default_server;
|
||||
|
||||
# With a server_name directive you can also ask NGINX to
|
||||
# use this server block only with matching server name(s)
|
||||
# listen 443 ssl http2;
|
||||
# listen [::]:443 ssl http2;
|
||||
# listen 443 ssl;
|
||||
# listen [::]:443 ssl;
|
||||
# server_name example.tld;
|
||||
|
||||
# Enable HTTP/2 support
|
||||
http2 on;
|
||||
|
||||
# Your SSL/TLS certificate (chain) and secret key in the PEM format
|
||||
ssl_certificate /path/to/fullchain.pem;
|
||||
ssl_certificate_key /path/to/private.pem;
|
||||
@@ -283,7 +285,7 @@ server {
|
||||
## Kubernetes
|
||||
<a id="kubernetes"></a>
|
||||
|
||||
The `readinessProbe` uses [(by
|
||||
The `readinessProbe` uses ([by
|
||||
default](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes))
|
||||
the pod IP as the hostname. Fastify listens on `127.0.0.1` by default. The probe
|
||||
will not be able to reach the application in this case. To make it work,
|
||||
@@ -305,22 +307,22 @@ readinessProbe:
|
||||
## Capacity Planning For Production
|
||||
<a id="capacity"></a>
|
||||
|
||||
In order to rightsize the production environment for your Fastify application,
|
||||
it is highly recommended that you perform your own measurements against
|
||||
In order to rightsize the production environment for your Fastify application,
|
||||
it is highly recommended that you perform your own measurements against
|
||||
different configurations of the environment, which may
|
||||
use real CPU cores, virtual CPU cores (vCPU), or even fractional
|
||||
vCPU cores. We will use the term vCPU throughout this
|
||||
recommendation to represent any CPU type.
|
||||
|
||||
Tools such as [k6](https://github.com/grafana/k6)
|
||||
Tools such as [k6](https://github.com/grafana/k6)
|
||||
or [autocannon](https://github.com/mcollina/autocannon) can be used for
|
||||
conducting the necessary performance tests.
|
||||
|
||||
That said, you may also consider the following as a rule of thumb:
|
||||
|
||||
* To have the lowest possible latency, 2 vCPU are recommended per app
|
||||
instance (e.g., a k8s pod). The second vCPU will mostly be used by the
|
||||
garbage collector (GC) and libuv threadpool. This will minimize the latency
|
||||
* To have the lowest possible latency, 2 vCPU are recommended per app
|
||||
instance (e.g., a k8s pod). The second vCPU will mostly be used by the
|
||||
garbage collector (GC) and libuv threadpool. This will minimize the latency
|
||||
for your users, as well as the memory usage, as the GC will be run more
|
||||
frequently. Also, the main thread won't have to stop to let the GC run.
|
||||
|
||||
@@ -328,7 +330,7 @@ frequently. Also, the main thread won't have to stop to let the GC run.
|
||||
requests per second per vCPU available), consider using a smaller amount of vCPUs
|
||||
per app instance. It is totally fine to run Node.js applications with 1 vCPU.
|
||||
|
||||
* You may experiment with an even smaller amount of vCPU, which may provide
|
||||
* You may experiment with an even smaller amount of vCPU, which may provide
|
||||
even better throughput in certain use-cases. There are reports of API gateway
|
||||
solutions working well with 100m-200m vCPU in Kubernetes.
|
||||
|
||||
@@ -345,7 +347,7 @@ would be exposing metrics endpoints on a separate port,
|
||||
to prevent public access, when using a reverse proxy or an ingress
|
||||
firewall is not an option.
|
||||
|
||||
It is perfectly fine to spin up several Fastify instances within the same
|
||||
Node.js process and run them concurrently, even in high load systems.
|
||||
It is perfectly fine to spin up several Fastify instances within the same
|
||||
Node.js process and run them concurrently, even in high load systems.
|
||||
Each Fastify instance only generates as much load as the traffic it receives,
|
||||
plus the memory used for that Fastify instance.
|
||||
|
||||
189
backend/node_modules/fastify/docs/Guides/Serverless.md
generated
vendored
189
backend/node_modules/fastify/docs/Guides/Serverless.md
generated
vendored
@@ -1,20 +1,20 @@
|
||||
<h1 align="center">Serverless</h1>
|
||||
|
||||
Run serverless applications and REST APIs using your existing Fastify
|
||||
application. By default, Fastify will not work on your serverless platform of
|
||||
choice, you will need to make some small changes to fix this. This document
|
||||
contains a small guide for the most popular serverless providers and how to use
|
||||
application. You may need to make code changes to work on your
|
||||
serverless platform of choice. This document contains a small guide
|
||||
for the most popular serverless providers and how to use
|
||||
Fastify with them.
|
||||
|
||||
#### Should you use Fastify in a serverless platform?
|
||||
|
||||
That is up to you! Keep in mind that functions as a service should always use
|
||||
That is up to you! Keep in mind, functions as a service should always use
|
||||
small and focused functions, but you can also run an entire web application with
|
||||
them. It is important to remember that the bigger the application the slower the
|
||||
initial boot will be. The best way to run Fastify applications in serverless
|
||||
environments is to use platforms like Google Cloud Run, AWS Fargate, and Azure
|
||||
Container Instances, where the server can handle multiple requests at the same
|
||||
time and make full use of Fastify's features.
|
||||
environments is to use platforms like Google Cloud Run, AWS Fargate, Azure
|
||||
Container Instances, and Vercel where the server can handle multiple requests
|
||||
at the same time and make full use of Fastify's features.
|
||||
|
||||
One of the best features of using Fastify in serverless applications is the ease
|
||||
of development. In your local environment, you will always run the Fastify
|
||||
@@ -25,21 +25,21 @@ snippet of code.
|
||||
### Contents
|
||||
|
||||
- [AWS](#aws)
|
||||
- [Genezio](#genezio)
|
||||
- [Google Cloud Functions](#google-cloud-functions)
|
||||
- [Google Firebase Functions](#google-firebase-functions)
|
||||
- [Google Cloud Run](#google-cloud-run)
|
||||
- [Netlify Lambda](#netlify-lambda)
|
||||
- [Platformatic Cloud](#platformatic-cloud)
|
||||
- [Vercel](#vercel)
|
||||
|
||||
## AWS
|
||||
|
||||
To integrate with AWS, you have two choices of library:
|
||||
|
||||
- Using [@fastify/aws-lambda](https://github.com/fastify/aws-lambda-fastify)
|
||||
- Using [@fastify/aws-lambda](https://github.com/fastify/aws-lambda-fastify)
|
||||
which only adds API Gateway support but has heavy optimizations for fastify.
|
||||
- Using [@h4ad/serverless-adapter](https://github.com/H4ad/serverless-adapter)
|
||||
which is a little slower as it creates an HTTP request for each AWS event but
|
||||
- Using [@h4ad/serverless-adapter](https://github.com/H4ad/serverless-adapter)
|
||||
which is a little slower as it creates an HTTP request for each AWS event but
|
||||
has support for more AWS services such as: AWS SQS, AWS SNS and others.
|
||||
|
||||
So you can decide which option is best for you, but you can test both libraries.
|
||||
@@ -129,6 +129,13 @@ If you need to integrate with more AWS services, take a look at
|
||||
[@h4ad/serverless-adapter](https://viniciusl.com.br/serverless-adapter/docs/main/frameworks/fastify)
|
||||
on Fastify to find out how to integrate.
|
||||
|
||||
## Genezio
|
||||
|
||||
[Genezio](https://genezio.com/) is a platform designed to simplify the deployment
|
||||
of serverless applications to the cloud.
|
||||
|
||||
[Genezio has a dedicated guide for deploying a Fastify application.](https://genezio.com/docs/frameworks/fastify/)
|
||||
|
||||
## Google Cloud Functions
|
||||
|
||||
### Creation of Fastify instance
|
||||
@@ -230,14 +237,13 @@ npx @google-cloud/functions-framework --target=fastifyFunction
|
||||
Or add this command to your `package.json` scripts:
|
||||
```json
|
||||
"scripts": {
|
||||
...
|
||||
"dev": "npx @google-cloud/functions-framework --target=fastifyFunction"
|
||||
...
|
||||
...
|
||||
"dev": "npx @google-cloud/functions-framework --target=fastifyFunction"
|
||||
...
|
||||
}
|
||||
```
|
||||
and run it with `npm run dev`.
|
||||
|
||||
|
||||
### Deploy
|
||||
```bash
|
||||
gcloud functions deploy fastifyFunction \
|
||||
@@ -263,7 +269,7 @@ curl -X POST https://$GOOGLE_REGION-$GOOGLE_PROJECT.cloudfunctions.net/me \
|
||||
|
||||
## Google Firebase Functions
|
||||
|
||||
Follow this guide if you want to use Fastify as the HTTP framework for
|
||||
Follow this guide if you want to use Fastify as the HTTP framework for
|
||||
Firebase Functions instead of the vanilla JavaScript router provided with
|
||||
`onRequest(async (req, res) => {}`.
|
||||
|
||||
@@ -280,8 +286,8 @@ const { onRequest } = require("firebase-functions/v2/https")
|
||||
### Creation of Fastify instance
|
||||
|
||||
Create the Fastify instance and encapsulate the returned application instance
|
||||
in a function which will register routes, await the server's processing of
|
||||
plugins, hooks and other settings. As follows:
|
||||
in a function that will register routes, await the server's processing of
|
||||
plugins, hooks, and other settings. As follows:
|
||||
|
||||
```js
|
||||
const fastify = require("fastify")({
|
||||
@@ -297,10 +303,10 @@ const fastifyApp = async (request, reply) => {
|
||||
|
||||
### Add Custom `contentTypeParser` to Fastify instance and define endpoints
|
||||
|
||||
Firebase Function's HTTP layer already parses the request
|
||||
and makes a JSON payload available. It also provides access
|
||||
to the raw body, unparsed, which is useful in order to calculate
|
||||
request signatures to validate HTTP webhooks.
|
||||
Firebase Function's HTTP layer already parses the request and makes a JSON
|
||||
payload available through the property `payload.body` below. It also provides
|
||||
access to the raw body, unparsed, which is useful for calculating request
|
||||
signatures to validate HTTP webhooks.
|
||||
|
||||
Add as follows to the `registerRoutes()` function:
|
||||
|
||||
@@ -318,7 +324,7 @@ async function registerRoutes (fastify) {
|
||||
})
|
||||
|
||||
// define your endpoints here...
|
||||
fastify.post("/some-route-here", async (request, reply) => {}
|
||||
fastify.post("/some-route-here", async (request, reply) => {})
|
||||
|
||||
fastify.get('/', async (request, reply) => {
|
||||
reply.send({message: 'Hello World!'})
|
||||
@@ -326,6 +332,24 @@ async function registerRoutes (fastify) {
|
||||
}
|
||||
```
|
||||
|
||||
**Failing to add this `ContentTypeParser` may lead to the Fastify process
|
||||
remaining stuck and not processing any other requests after receiving one with
|
||||
the Content-Type `application/json`.**
|
||||
|
||||
When using Typescript, since the type of `payload` is a native `IncomingMessage`
|
||||
that gets modified by Firebase, it won't be able to find the property
|
||||
`payload.body`.
|
||||
|
||||
In order to suppress the error, you can use the following signature:
|
||||
|
||||
```ts
|
||||
declare module 'http' {
|
||||
interface IncomingMessage {
|
||||
body?: unknown;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Export the function using Firebase onRequest
|
||||
|
||||
Final step is to export the Fastify app instance to Firebase's own
|
||||
@@ -369,7 +393,6 @@ firebase functions:log
|
||||
- [Fastify on Firebase Functions](https://github.com/lirantal/lemon-squeezy-firebase-webhook-fastify/blob/main/package.json)
|
||||
- [An article about HTTP webhooks on Firebase Functions and Fastify: A Practical Case Study with Lemon Squeezy](https://lirantal.com/blog/http-webhooks-firebase-functions-fastify-practical-case-study-lemon-squeezy)
|
||||
|
||||
|
||||
## Google Cloud Run
|
||||
|
||||
Unlike AWS Lambda or Google Cloud Functions, Google Cloud Run is a serverless
|
||||
@@ -384,7 +407,7 @@ familiar with gcloud or just follow their
|
||||
|
||||
### Adjust Fastify server
|
||||
|
||||
In order for Fastify to properly listen for requests within the container, be
|
||||
For Fastify to properly listen for requests within the container, be
|
||||
sure to set the correct port and address:
|
||||
|
||||
```js
|
||||
@@ -455,7 +478,7 @@ CMD [ "npm", "start" ]
|
||||
To keep build artifacts out of your container (which keeps it small and improves
|
||||
build times) add a `.dockerignore` file like the one below:
|
||||
|
||||
```.dockerignore
|
||||
```dockerignore
|
||||
Dockerfile
|
||||
README.md
|
||||
node_modules
|
||||
@@ -482,12 +505,11 @@ gcloud beta run deploy --image gcr.io/PROJECT-ID/APP-NAME --platform managed
|
||||
|
||||
Your app will be accessible from the URL GCP provides.
|
||||
|
||||
|
||||
## netlify-lambda
|
||||
|
||||
First, please perform all preparation steps related to **AWS Lambda**.
|
||||
|
||||
Create a folder called `functions`, then create `server.js` (and your endpoint
|
||||
Create a folder called `functions`, then create `server.js` (and your endpoint
|
||||
path will be `server.js`) inside the `functions` folder.
|
||||
|
||||
### functions/server.js
|
||||
@@ -556,106 +578,27 @@ Add this command to your `package.json` *scripts*
|
||||
|
||||
```json
|
||||
"scripts": {
|
||||
...
|
||||
"build:functions": "netlify-lambda build functions --config ./webpack.config.netlify.js"
|
||||
...
|
||||
...
|
||||
"build:functions": "netlify-lambda build functions --config ./webpack.config.netlify.js"
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Then it should work fine
|
||||
|
||||
## Platformatic Cloud
|
||||
|
||||
[Platformatic](https://platformatic.dev) provides zero-configuration deployment
|
||||
for Node.js applications.
|
||||
To use it now, you should wrap your existing Fastify application inside a
|
||||
[Platformatic Service](https://oss.platformatic.dev/docs/reference/service/introduction),
|
||||
by running the following:
|
||||
|
||||
|
||||
```bash
|
||||
npm create platformatic@latest -- service
|
||||
```
|
||||
|
||||
The wizard would ask you to fill in a few answers:
|
||||
|
||||
```
|
||||
? Where would you like to create your project? .
|
||||
? Do you want to run npm install? yes
|
||||
? Do you want to use TypeScript? no
|
||||
? What port do you want to use? 3042
|
||||
[13:04:14] INFO: Configuration file platformatic.service.json successfully created.
|
||||
[13:04:14] INFO: Environment file .env successfully created.
|
||||
[13:04:14] INFO: Plugins folder "plugins" successfully created.
|
||||
[13:04:14] INFO: Routes folder "routes" successfully created.
|
||||
? Do you want to create the github action to deploy this application to Platformatic Cloud dynamic workspace? no
|
||||
? Do you want to create the github action to deploy this application to Platformatic Cloud static workspace? no
|
||||
```
|
||||
|
||||
Then, head to [Platformatic Cloud](https://platformatic.cloud) and sign in
|
||||
with your GitHub account.
|
||||
Create your first application and a static workspace: be careful to download the
|
||||
API key as an env file, e.g. `yourworkspace.txt`.
|
||||
|
||||
Then, you can easily deploy your application with the following command:
|
||||
|
||||
```bash
|
||||
platformatic deploy --keys `yourworkspace.txt`
|
||||
```
|
||||
|
||||
Check out the [Full Guide](https://blog.platformatic.dev/how-to-migrate-a-fastify-app-to-platformatic-service)
|
||||
on how to wrap Fastify application in Platformatic.
|
||||
Then it should work fine.
|
||||
|
||||
## Vercel
|
||||
|
||||
[Vercel](https://vercel.com) provides zero-configuration deployment for Node.js
|
||||
applications. To use it now, it is as simple as configuring your `vercel.json`
|
||||
file like the following:
|
||||
[Vercel](https://vercel.com) fully supports deploying Fastify applications.
|
||||
Additionally, with Vercel's
|
||||
[Fluid compute](https://vercel.com/docs/functions/fluid-compute), you can combine
|
||||
server-like concurrency with the autoscaling properties of traditional
|
||||
serverless functions.
|
||||
|
||||
```json
|
||||
{
|
||||
"rewrites": [
|
||||
{
|
||||
"source": "/(.*)",
|
||||
"destination": "/api/serverless.js"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Get started with the
|
||||
[Fastify template on Vercel](
|
||||
https://vercel.com/templates/backend/fastify-on-vercel).
|
||||
|
||||
Then, write `api/serverless.js` like so:
|
||||
|
||||
```js
|
||||
"use strict";
|
||||
|
||||
// Read the .env file.
|
||||
import * as dotenv from "dotenv";
|
||||
dotenv.config();
|
||||
|
||||
// Require the framework
|
||||
import Fastify from "fastify";
|
||||
|
||||
// Instantiate Fastify with some config
|
||||
const app = Fastify({
|
||||
logger: true,
|
||||
});
|
||||
|
||||
// Register your application as a normal plugin.
|
||||
app.register(import("../src/app.js"));
|
||||
|
||||
export default async (req, res) => {
|
||||
await app.ready();
|
||||
app.server.emit('request', req, res);
|
||||
}
|
||||
```
|
||||
|
||||
In `src/app.js` define the plugin.
|
||||
```js
|
||||
async function routes (fastify, options) {
|
||||
fastify.get('/', async (request, reply) => {
|
||||
return { hello: 'world' }
|
||||
})
|
||||
}
|
||||
|
||||
export default routes;
|
||||
```
|
||||
[Fluid compute](https://vercel.com/docs/functions/fluid-compute) currently
|
||||
requires an explicit opt-in. Learn more about enabling Fluid compute
|
||||
[here](
|
||||
https://vercel.com/docs/functions/fluid-compute#how-to-enable-fluid-compute).
|
||||
4
backend/node_modules/fastify/docs/Guides/Style-Guide.md
generated
vendored
4
backend/node_modules/fastify/docs/Guides/Style-Guide.md
generated
vendored
@@ -83,7 +83,7 @@ Result:
|
||||
|
||||
Make sure you avoid copying other people's work. Keep it as original as
|
||||
possible. You can learn from what they have done and reference where it is from
|
||||
if you used a particular quote from their work.
|
||||
if you use a particular quote from their work.
|
||||
|
||||
|
||||
## Word Choice
|
||||
@@ -217,7 +217,7 @@ Styles](https://medium.com/better-programming/string-case-styles-camel-pascal-sn
|
||||
|
||||
### Hyperlinks
|
||||
|
||||
Hyperlinks should have a clear title of what it references. Here is how your
|
||||
Hyperlinks should have a clear title of what they reference. Here is how your
|
||||
hyperlink should look:
|
||||
|
||||
```MD
|
||||
|
||||
121
backend/node_modules/fastify/docs/Guides/Testing.md
generated
vendored
121
backend/node_modules/fastify/docs/Guides/Testing.md
generated
vendored
@@ -5,15 +5,15 @@
|
||||
|
||||
Testing is one of the most important parts of developing an application. Fastify
|
||||
is very flexible when it comes to testing and is compatible with most testing
|
||||
frameworks (such as [Tap](https://www.npmjs.com/package/tap), which is used in
|
||||
the examples below).
|
||||
frameworks (such as [Node Test Runner](https://nodejs.org/api/test.html),
|
||||
which is used in the examples below).
|
||||
|
||||
## Application
|
||||
|
||||
Let's `cd` into a fresh directory called 'testing-example' and type `npm init
|
||||
-y` in our terminal.
|
||||
|
||||
Run `npm i fastify && npm i tap pino-pretty -D`
|
||||
Run `npm i fastify && npm i pino-pretty -D`
|
||||
|
||||
### Separating concerns makes testing easy
|
||||
|
||||
@@ -113,24 +113,25 @@ Now we can replace our `console.log` calls with actual tests!
|
||||
|
||||
In your `package.json` change the "test" script to:
|
||||
|
||||
`"test": "tap --reporter=list --watch"`
|
||||
`"test": "node --test --watch"`
|
||||
|
||||
**app.test.js**:
|
||||
|
||||
```js
|
||||
'use strict'
|
||||
|
||||
const { test } = require('tap')
|
||||
const { test } = require('node:test')
|
||||
const build = require('./app')
|
||||
|
||||
test('requests the "/" route', async t => {
|
||||
t.plan(1)
|
||||
const app = build()
|
||||
|
||||
const response = await app.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
})
|
||||
t.equal(response.statusCode, 200, 'returns a status code of 200')
|
||||
t.assert.strictEqual(response.statusCode, 200, 'returns a status code of 200')
|
||||
})
|
||||
```
|
||||
|
||||
@@ -214,26 +215,26 @@ module.exports = buildFastify
|
||||
|
||||
**test.js**
|
||||
```js
|
||||
const tap = require('tap')
|
||||
const { test } = require('node:test')
|
||||
const buildFastify = require('./app')
|
||||
|
||||
tap.test('GET `/` route', t => {
|
||||
test('GET `/` route', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = buildFastify()
|
||||
|
||||
// At the end of your tests it is highly recommended to call `.close()`
|
||||
// to ensure that all connections to external services get closed.
|
||||
t.teardown(() => fastify.close())
|
||||
t.after(() => fastify.close())
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(response.headers['content-type'], 'application/json; charset=utf-8')
|
||||
t.same(response.json(), { hello: 'world' })
|
||||
t.assert.ifError(err)
|
||||
t.assert.strictEqual(response.statusCode, 200)
|
||||
t.assert.strictEqual(response.headers['content-type'], 'application/json; charset=utf-8')
|
||||
t.assert.deepStrictEqual(response.json(), { hello: 'world' })
|
||||
})
|
||||
})
|
||||
```
|
||||
@@ -248,11 +249,11 @@ Uses **app.js** from the previous example.
|
||||
|
||||
**test-listen.js** (testing with [`undici`](https://www.npmjs.com/package/undici))
|
||||
```js
|
||||
const tap = require('tap')
|
||||
const { test } = require('node:test')
|
||||
const { Client } = require('undici')
|
||||
const buildFastify = require('./app')
|
||||
|
||||
tap.test('should work with undici', async t => {
|
||||
test('should work with undici', async t => {
|
||||
t.plan(2)
|
||||
|
||||
const fastify = buildFastify()
|
||||
@@ -263,63 +264,64 @@ tap.test('should work with undici', async t => {
|
||||
'http://localhost:' + fastify.server.address().port, {
|
||||
keepAliveTimeout: 10,
|
||||
keepAliveMaxTimeout: 10
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
t.teardown(() => {
|
||||
t.after(() => {
|
||||
fastify.close()
|
||||
client.close()
|
||||
})
|
||||
|
||||
const response = await client.request({ method: 'GET', path: '/' })
|
||||
|
||||
t.equal(await response.body.text(), '{"hello":"world"}')
|
||||
t.equal(response.statusCode, 200)
|
||||
t.assert.strictEqual(await response.body.text(), '{"hello":"world"}')
|
||||
t.assert.strictEqual(response.statusCode, 200)
|
||||
})
|
||||
```
|
||||
|
||||
Alternatively, starting with Node.js 18,
|
||||
[`fetch`](https://nodejs.org/docs/latest-v18.x/api/globals.html#fetch)
|
||||
Alternatively, starting with Node.js 18,
|
||||
[`fetch`](https://nodejs.org/docs/latest-v18.x/api/globals.html#fetch)
|
||||
may be used without requiring any extra dependencies:
|
||||
|
||||
**test-listen.js**
|
||||
```js
|
||||
const tap = require('tap')
|
||||
const { test } = require('node:test')
|
||||
const buildFastify = require('./app')
|
||||
|
||||
tap.test('should work with fetch', async t => {
|
||||
test('should work with fetch', async t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = buildFastify()
|
||||
|
||||
t.teardown(() => fastify.close())
|
||||
t.after(() => fastify.close())
|
||||
|
||||
await fastify.listen()
|
||||
|
||||
|
||||
const response = await fetch(
|
||||
'http://localhost:' + fastify.server.address().port
|
||||
)
|
||||
|
||||
t.equal(response.status, 200)
|
||||
t.equal(
|
||||
t.assert.strictEqual(response.status, 200)
|
||||
t.assert.strictEqual(
|
||||
response.headers.get('content-type'),
|
||||
'application/json; charset=utf-8'
|
||||
)
|
||||
t.has(await response.json(), { hello: 'world' })
|
||||
const jsonResult = await response.json()
|
||||
t.assert.strictEqual(jsonResult.hello, 'world')
|
||||
})
|
||||
```
|
||||
|
||||
**test-ready.js** (testing with
|
||||
[`SuperTest`](https://www.npmjs.com/package/supertest))
|
||||
```js
|
||||
const tap = require('tap')
|
||||
const { test } = require('node:test')
|
||||
const supertest = require('supertest')
|
||||
const buildFastify = require('./app')
|
||||
|
||||
tap.test('GET `/` route', async (t) => {
|
||||
test('GET `/` route', async (t) => {
|
||||
const fastify = buildFastify()
|
||||
|
||||
t.teardown(() => fastify.close())
|
||||
t.after(() => fastify.close())
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
@@ -327,22 +329,21 @@ tap.test('GET `/` route', async (t) => {
|
||||
.get('/')
|
||||
.expect(200)
|
||||
.expect('Content-Type', 'application/json; charset=utf-8')
|
||||
t.same(response.body, { hello: 'world' })
|
||||
t.assert.deepStrictEqual(response.body, { hello: 'world' })
|
||||
})
|
||||
```
|
||||
|
||||
### How to inspect tap tests
|
||||
### How to inspect node tests
|
||||
1. Isolate your test by passing the `{only: true}` option
|
||||
```javascript
|
||||
test('should ...', {only: true}, t => ...)
|
||||
```
|
||||
2. Run `tap` using `npx`
|
||||
2. Run `node --test`
|
||||
```bash
|
||||
> npx tap -O -T --node-arg=--inspect-brk test/<test-file.test.js>
|
||||
> node --test --test-only --inspect-brk test/<test-file.test.js>
|
||||
```
|
||||
- `-O` specifies to run tests with the `only` option enabled
|
||||
- `-T` specifies not to timeout (while you're debugging)
|
||||
- `--node-arg=--inspect-brk` will launch the node debugger
|
||||
- `--test-only` specifies to run tests with the `only` option enabled
|
||||
- `--inspect-brk` will launch the node debugger
|
||||
3. In VS Code, create and launch a `Node.js: Attach` debug configuration. No
|
||||
modification should be necessary.
|
||||
|
||||
@@ -352,10 +353,10 @@ Now you should be able to step through your test file (and the rest of
|
||||
|
||||
|
||||
## Plugins
|
||||
Let's `cd` into a fresh directory called 'testing-plugin-example' and type `npm init
|
||||
-y` in our terminal.
|
||||
Let's `cd` into a fresh directory called 'testing-plugin-example' and type
|
||||
`npm init -y` in our terminal.
|
||||
|
||||
Run `npm i fastify fastify-plugin && npm i tap -D`
|
||||
Run `npm i fastify fastify-plugin`
|
||||
|
||||
**plugin/myFirstPlugin.js**:
|
||||
|
||||
@@ -376,16 +377,16 @@ A basic example of a Plugin. See [Plugin Guide](./Plugins-Guide.md)
|
||||
|
||||
```js
|
||||
const Fastify = require("fastify");
|
||||
const tap = require("tap");
|
||||
const { test } = require("node:test");
|
||||
const myPlugin = require("../plugin/myFirstPlugin");
|
||||
|
||||
tap.test("Test the Plugin Route", async t => {
|
||||
test("Test the Plugin Route", async t => {
|
||||
// Create a mock fastify application to test the plugin
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(myPlugin)
|
||||
|
||||
// Add an endpoint of your choice
|
||||
// Add an endpoint of your choice
|
||||
fastify.get("/", async (request, reply) => {
|
||||
return ({ message: request.helloRequest })
|
||||
})
|
||||
@@ -395,7 +396,7 @@ tap.test("Test the Plugin Route", async t => {
|
||||
method: "GET",
|
||||
url: "/"
|
||||
})
|
||||
|
||||
|
||||
console.log('status code: ', fastifyResponse.statusCode)
|
||||
console.log('body: ', fastifyResponse.body)
|
||||
})
|
||||
@@ -412,18 +413,18 @@ Now we can replace our `console.log` calls with actual tests!
|
||||
|
||||
In your `package.json` change the "test" script to:
|
||||
|
||||
`"test": "tap --reporter=list --watch"`
|
||||
`"test": "node --test --watch"`
|
||||
|
||||
Create the tap test for the endpoint.
|
||||
Create the test for the endpoint.
|
||||
|
||||
**test/myFirstPlugin.test.js**:
|
||||
|
||||
```js
|
||||
const Fastify = require("fastify");
|
||||
const tap = require("tap");
|
||||
const { test } = require("node:test");
|
||||
const myPlugin = require("../plugin/myFirstPlugin");
|
||||
|
||||
tap.test("Test the Plugin Route", async t => {
|
||||
test("Test the Plugin Route", async t => {
|
||||
// Specifies the number of test
|
||||
t.plan(2)
|
||||
|
||||
@@ -439,9 +440,9 @@ tap.test("Test the Plugin Route", async t => {
|
||||
method: "GET",
|
||||
url: "/"
|
||||
})
|
||||
|
||||
t.equal(fastifyResponse.statusCode, 200)
|
||||
t.same(JSON.parse(fastifyResponse.body), { message: "Hello World" })
|
||||
|
||||
t.assert.strictEqual(fastifyResponse.statusCode, 200)
|
||||
t.assert.deepStrictEqual(JSON.parse(fastifyResponse.body), { message: "Hello World" })
|
||||
})
|
||||
```
|
||||
|
||||
@@ -453,10 +454,10 @@ Test the ```.decorate()``` and ```.decorateRequest()```.
|
||||
|
||||
```js
|
||||
const Fastify = require("fastify");
|
||||
const tap = require("tap");
|
||||
const { test }= require("node:test");
|
||||
const myPlugin = require("../plugin/myFirstPlugin");
|
||||
|
||||
tap.test("Test the Plugin Route", async t => {
|
||||
test("Test the Plugin Route", async t => {
|
||||
t.plan(5)
|
||||
const fastify = Fastify()
|
||||
|
||||
@@ -464,9 +465,9 @@ tap.test("Test the Plugin Route", async t => {
|
||||
|
||||
fastify.get("/", async (request, reply) => {
|
||||
// Testing the fastify decorators
|
||||
t.not(request.helloRequest, null)
|
||||
t.ok(request.helloRequest, "Hello World")
|
||||
t.ok(fastify.helloInstance, "Hello Fastify Instance")
|
||||
t.assert.ifError(request.helloRequest)
|
||||
t.assert.ok(request.helloRequest, "Hello World")
|
||||
t.assert.ok(fastify.helloInstance, "Hello Fastify Instance")
|
||||
return ({ message: request.helloRequest })
|
||||
})
|
||||
|
||||
@@ -474,7 +475,7 @@ tap.test("Test the Plugin Route", async t => {
|
||||
method: "GET",
|
||||
url: "/"
|
||||
})
|
||||
t.equal(fastifyResponse.statusCode, 200)
|
||||
t.same(JSON.parse(fastifyResponse.body), { message: "Hello World" })
|
||||
t.assert.strictEqual(fastifyResponse.statusCode, 200)
|
||||
t.assert.deepStrictEqual(JSON.parse(fastifyResponse.body), { message: "Hello World" })
|
||||
})
|
||||
```
|
||||
```
|
||||
|
||||
9
backend/node_modules/fastify/docs/Guides/Write-Plugin.md
generated
vendored
9
backend/node_modules/fastify/docs/Guides/Write-Plugin.md
generated
vendored
@@ -14,7 +14,7 @@ suggestion"](https://github.com/fastify/fastify/issues?q=is%3Aissue+is%3Aopen+la
|
||||
in our issue tracker!*
|
||||
|
||||
## Code
|
||||
Fastify uses different techniques to optimize its code, many of them are
|
||||
Fastify uses different techniques to optimize its code, many of which are
|
||||
documented in our Guides. We highly recommend you read [the hitchhiker's guide
|
||||
to plugins](./Plugins-Guide.md) to discover all the APIs you can use to build
|
||||
your plugin and learn how to use them.
|
||||
@@ -53,17 +53,16 @@ Always put an example file in your repository. Examples are very helpful for
|
||||
users and give a very fast way to test your plugin. Your users will be grateful.
|
||||
|
||||
## Test
|
||||
It is extremely important that a plugin is thoroughly tested to verify that is
|
||||
working properly.
|
||||
A plugin **must** be thoroughly tested to verify that is working properly.
|
||||
|
||||
A plugin without tests will not be accepted to the ecosystem list. A lack of
|
||||
tests does not inspire trust nor guarantee that the code will continue to work
|
||||
among different versions of its dependencies.
|
||||
|
||||
We do not enforce any testing library. We use [`tap`](https://www.node-tap.org/)
|
||||
We do not enforce any testing library. We use [`node:test`](https://nodejs.org/api/test.html)
|
||||
since it offers out-of-the-box parallel testing and code coverage, but it is up
|
||||
to you to choose your library of preference.
|
||||
We highly recommend you read the [Plugin Testing](./Testing.md#plugins) to
|
||||
We highly recommend you read the [Plugin Testing](./Testing.md#plugins) to
|
||||
learn about how to test your plugins.
|
||||
|
||||
## Code Linter
|
||||
|
||||
12
backend/node_modules/fastify/docs/Guides/Write-Type-Provider.md
generated
vendored
12
backend/node_modules/fastify/docs/Guides/Write-Type-Provider.md
generated
vendored
@@ -10,16 +10,17 @@ Whereas exhaustive type narrowing checks normally rely on `never` to represent
|
||||
an unreachable state, reduction in type provider interfaces should only be done
|
||||
up to `unknown`.
|
||||
|
||||
The reasoning is that certain methods of `FastifyInstance` are
|
||||
contravariant on `TypeProvider`, which can lead to TypeScript surfacing
|
||||
assignability issues unless the custom type provider interface is
|
||||
The reasoning is that certain methods of `FastifyInstance` are
|
||||
contravariant on `TypeProvider`, which can lead to TypeScript surfacing
|
||||
assignability issues unless the custom type provider interface is
|
||||
substitutable with `FastifyTypeProviderDefault`.
|
||||
|
||||
For example, `FastifyTypeProviderDefault` will not be assignable to the following:
|
||||
```ts
|
||||
export interface NotSubstitutableTypeProvider extends FastifyTypeProvider {
|
||||
// bad, nothing is assignable to `never` (except for itself)
|
||||
output: this['input'] extends /** custom check here**/ ? /** narrowed type here **/ : never;
|
||||
validator: this['schema'] extends /** custom check here**/ ? /** narrowed type here **/ : never;
|
||||
serializer: this['schema'] extends /** custom check here**/ ? /** narrowed type here **/ : never;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -27,6 +28,7 @@ Unless changed to:
|
||||
```ts
|
||||
export interface SubstitutableTypeProvider extends FastifyTypeProvider {
|
||||
// good, anything can be assigned to `unknown`
|
||||
output: this['input'] extends /** custom check here**/ ? /** narrowed type here **/ : unknown;
|
||||
validator: this['schema'] extends /** custom check here**/ ? /** narrowed type here **/ : unknown;
|
||||
serializer: this['schema'] extends /** custom check here**/ ? /** narrowed type here **/ : unknown;
|
||||
}
|
||||
```
|
||||
|
||||
155
backend/node_modules/fastify/docs/Reference/ContentTypeParser.md
generated
vendored
155
backend/node_modules/fastify/docs/Reference/ContentTypeParser.md
generated
vendored
@@ -1,33 +1,34 @@
|
||||
<h1 align="center">Fastify</h1>
|
||||
|
||||
## `Content-Type` Parser
|
||||
Natively, Fastify only supports `'application/json'` and `'text/plain'` content
|
||||
types. If the content type is not one of these, an
|
||||
`FST_ERR_CTP_INVALID_MEDIA_TYPE` error will be thrown.
|
||||
Other common content types are supported through the use of
|
||||
[plugins](https://fastify.dev/ecosystem/).
|
||||
Fastify natively supports `'application/json'` and `'text/plain'` content types
|
||||
with a default charset of `utf-8`. These default parsers can be changed or
|
||||
removed.
|
||||
|
||||
The default charset is `utf-8`. If you need to support different content types,
|
||||
you can use the `addContentTypeParser` API. *The default JSON and/or plain text
|
||||
parser can be changed or removed.*
|
||||
Unsupported content types will throw an `FST_ERR_CTP_INVALID_MEDIA_TYPE` error.
|
||||
|
||||
*Note: If you decide to specify your own content type with the `Content-Type`
|
||||
header, UTF-8 will not be the default. Be sure to include UTF-8 like this
|
||||
`text/html; charset=utf-8`.*
|
||||
To support other content types, use the `addContentTypeParser` API or an
|
||||
existing [plugin](https://fastify.dev/ecosystem/).
|
||||
|
||||
As with the other APIs, `addContentTypeParser` is encapsulated in the scope in
|
||||
which it is declared. This means that if you declare it in the root scope it
|
||||
will be available everywhere, while if you declare it inside a plugin it will be
|
||||
available only in that scope and its children.
|
||||
As with other APIs, `addContentTypeParser` is encapsulated in the scope in which
|
||||
it is declared. If declared in the root scope, it is available everywhere; if
|
||||
declared in a plugin, it is available only in that scope and its children.
|
||||
|
||||
Fastify automatically adds the parsed request payload to the [Fastify
|
||||
request](./Request.md) object which you can access with `request.body`.
|
||||
request](./Request.md) object, accessible via `request.body`.
|
||||
|
||||
Note that for `GET` and `HEAD` requests the payload is never parsed. For
|
||||
`OPTIONS` and `DELETE` requests the payload is only parsed if the content type
|
||||
is given in the content-type header. If it is not given, the
|
||||
[catch-all](#catch-all) parser is not executed as with `POST`, `PUT` and
|
||||
`PATCH`, but the payload is simply not parsed.
|
||||
Note that for `GET` and `HEAD` requests, the payload is never parsed. For
|
||||
`OPTIONS` and `DELETE` requests, the payload is parsed only if a valid
|
||||
`content-type` header is provided. Unlike `POST`, `PUT`, and `PATCH`, the
|
||||
[catch-all](#catch-all) parser is not executed, and the payload is simply not
|
||||
parsed.
|
||||
|
||||
> ⚠ Warning:
|
||||
> When using regular expressions to detect `Content-Type`, it is important to
|
||||
> ensure proper detection. For example, to match `application/*`, use
|
||||
> `/^application\/([\w-]+);?/` to match the
|
||||
> [essence MIME type](https://mimesniff.spec.whatwg.org/#mime-type-miscellaneous)
|
||||
> only.
|
||||
|
||||
### Usage
|
||||
```js
|
||||
@@ -46,13 +47,13 @@ fastify.addContentTypeParser(['text/xml', 'application/xml'], function (request,
|
||||
|
||||
// Async is also supported in Node versions >= 8.0.0
|
||||
fastify.addContentTypeParser('application/jsoff', async function (request, payload) {
|
||||
var res = await jsoffParserAsync(payload)
|
||||
const res = await jsoffParserAsync(payload)
|
||||
|
||||
return res
|
||||
})
|
||||
|
||||
// Handle all content types that matches RegExp
|
||||
fastify.addContentTypeParser(/^image\/.*/, function (request, payload, done) {
|
||||
fastify.addContentTypeParser(/^image\/([\w-]+);?/, function (request, payload, done) {
|
||||
imageParser(payload, function (err, body) {
|
||||
done(err, body)
|
||||
})
|
||||
@@ -63,11 +64,10 @@ fastify.addContentTypeParser('text/json', { parseAs: 'string' }, fastify.getDefa
|
||||
```
|
||||
|
||||
Fastify first tries to match a content-type parser with a `string` value before
|
||||
trying to find a matching `RegExp`. If you provide overlapping content types,
|
||||
Fastify tries to find a matching content type by starting with the last one
|
||||
passed and ending with the first one. So if you want to specify a general
|
||||
content type more precisely, first specify the general content type and then the
|
||||
more specific one, like in the example below.
|
||||
trying to find a matching `RegExp`. For overlapping content types, it starts
|
||||
with the last one configured and ends with the first (last in, first out).
|
||||
To specify a general content type more precisely, first specify the general
|
||||
type, then the specific one, as shown below.
|
||||
|
||||
```js
|
||||
// Here only the second content type parser is called because its value also matches the first one
|
||||
@@ -80,14 +80,34 @@ fastify.addContentTypeParser('application/vnd.custom', (request, body, done) =>
|
||||
fastify.addContentTypeParser('application/vnd.custom+xml', (request, body, done) => {} )
|
||||
```
|
||||
|
||||
Besides the `addContentTypeParser` API there are further APIs that can be used.
|
||||
These are `hasContentTypeParser`, `removeContentTypeParser` and
|
||||
`removeAllContentTypeParsers`.
|
||||
### Using addContentTypeParser with fastify.register
|
||||
When using `addContentTypeParser` with `fastify.register`, avoid `await`
|
||||
when registering routes. Using `await` makes route registration asynchronous,
|
||||
potentially registering routes before `addContentTypeParser` is set.
|
||||
|
||||
#### Correct Usage
|
||||
```js
|
||||
const fastify = require('fastify')();
|
||||
|
||||
|
||||
fastify.register((fastify, opts) => {
|
||||
fastify.addContentTypeParser('application/json', function (request, payload, done) {
|
||||
jsonParser(payload, function (err, body) {
|
||||
done(err, body)
|
||||
})
|
||||
})
|
||||
|
||||
fastify.get('/hello', async (req, res) => {});
|
||||
});
|
||||
```
|
||||
|
||||
In addition to `addContentTypeParser`, the `hasContentTypeParser`,
|
||||
`removeContentTypeParser`, and `removeAllContentTypeParsers` APIs are available.
|
||||
|
||||
#### hasContentTypeParser
|
||||
|
||||
You can use the `hasContentTypeParser` API to find if a specific content type
|
||||
parser already exists.
|
||||
Use the `hasContentTypeParser` API to check if a specific content type parser
|
||||
exists.
|
||||
|
||||
```js
|
||||
if (!fastify.hasContentTypeParser('application/jsoff')){
|
||||
@@ -101,8 +121,8 @@ if (!fastify.hasContentTypeParser('application/jsoff')){
|
||||
|
||||
#### removeContentTypeParser
|
||||
|
||||
With `removeContentTypeParser` a single or an array of content types can be
|
||||
removed. The method supports `string` and `RegExp` content types.
|
||||
`removeContentTypeParser` can remove a single content type or an array of
|
||||
content types, supporting both `string` and `RegExp`.
|
||||
|
||||
```js
|
||||
fastify.addContentTypeParser('text/xml', function (request, payload, done) {
|
||||
@@ -116,16 +136,11 @@ fastify.removeContentTypeParser(['application/json', 'text/plain'])
|
||||
```
|
||||
|
||||
#### removeAllContentTypeParsers
|
||||
|
||||
In the example from just above, it is noticeable that we need to specify each
|
||||
content type that we want to remove. To solve this problem Fastify provides the
|
||||
`removeAllContentTypeParsers` API. This can be used to remove all currently
|
||||
existing content type parsers. In the example below we achieve the same as in
|
||||
the example above except that we do not need to specify each content type to
|
||||
delete. Just like `removeContentTypeParser`, this API supports encapsulation.
|
||||
The API is especially useful if you want to register a [catch-all content type
|
||||
parser](#catch-all) that should be executed for every content type and the
|
||||
built-in parsers should be ignored as well.
|
||||
The `removeAllContentTypeParsers` API removes all existing content type parsers
|
||||
eliminating the need to specify each one individually. This API supports
|
||||
encapsulation and is useful for registering a
|
||||
[catch-all content type parser](#catch-all) that should be executed for every
|
||||
content type, ignoring built-in parsers.
|
||||
|
||||
```js
|
||||
fastify.removeAllContentTypeParsers()
|
||||
@@ -137,22 +152,20 @@ fastify.addContentTypeParser('text/xml', function (request, payload, done) {
|
||||
})
|
||||
```
|
||||
|
||||
**Notice**: The old syntaxes `function(req, done)` and `async function(req)` for
|
||||
the parser are still supported but they are deprecated.
|
||||
> ℹ️ Note: `function(req, done)` and `async function(req)` are
|
||||
> still supported but deprecated.
|
||||
|
||||
#### Body Parser
|
||||
You can parse the body of a request in two ways. The first one is shown above:
|
||||
you add a custom content type parser and handle the request stream. In the
|
||||
second one, you should pass a `parseAs` option to the `addContentTypeParser`
|
||||
API, where you declare how you want to get the body. It could be of type
|
||||
`'string'` or `'buffer'`. If you use the `parseAs` option, Fastify will
|
||||
internally handle the stream and perform some checks, such as the [maximum
|
||||
size](./Server.md#factory-body-limit) of the body and the content length. If the
|
||||
limit is exceeded the custom parser will not be invoked.
|
||||
The request body can be parsed in two ways. First, add a custom content type
|
||||
parser and handle the request stream. Or second, use the `parseAs` option in the
|
||||
`addContentTypeParser` API, specifying `'string'` or `'buffer'`. Fastify will
|
||||
handle the stream, check the [maximum size](./Server.md#factory-body-limit) of
|
||||
the body, and the content length. If the limit is exceeded, the custom parser
|
||||
will not be invoked.
|
||||
```js
|
||||
fastify.addContentTypeParser('application/json', { parseAs: 'string' }, function (req, body, done) {
|
||||
try {
|
||||
var json = JSON.parse(body)
|
||||
const json = JSON.parse(body)
|
||||
done(null, json)
|
||||
} catch (err) {
|
||||
err.statusCode = 400
|
||||
@@ -166,30 +179,27 @@ See
|
||||
for an example.
|
||||
|
||||
##### Custom Parser Options
|
||||
+ `parseAs` (string): Either `'string'` or `'buffer'` to designate how the
|
||||
incoming data should be collected. Default: `'buffer'`.
|
||||
+ `parseAs` (string): `'string'` or `'buffer'` to designate how the incoming
|
||||
data should be collected. Default: `'buffer'`.
|
||||
+ `bodyLimit` (number): The maximum payload size, in bytes, that the custom
|
||||
parser will accept. Defaults to the global body limit passed to the [`Fastify
|
||||
factory function`](./Server.md#bodylimit).
|
||||
|
||||
#### Catch-All
|
||||
There are some cases where you need to catch all requests regardless of their
|
||||
content type. With Fastify, you can just use the `'*'` content type.
|
||||
To catch all requests regardless of content type, use the `'*'` content type:
|
||||
```js
|
||||
fastify.addContentTypeParser('*', function (request, payload, done) {
|
||||
var data = ''
|
||||
let data = ''
|
||||
payload.on('data', chunk => { data += chunk })
|
||||
payload.on('end', () => {
|
||||
done(null, data)
|
||||
})
|
||||
})
|
||||
```
|
||||
All requests without a corresponding content type parser will be handled by
|
||||
this function.
|
||||
|
||||
Using this, all requests that do not have a corresponding content type parser
|
||||
will be handled by the specified function.
|
||||
|
||||
This is also useful for piping the request stream. You can define a content
|
||||
parser like:
|
||||
This is also useful for piping the request stream. Define a content parser like:
|
||||
|
||||
```js
|
||||
fastify.addContentTypeParser('*', function (request, payload, done) {
|
||||
@@ -197,7 +207,7 @@ fastify.addContentTypeParser('*', function (request, payload, done) {
|
||||
})
|
||||
```
|
||||
|
||||
and then access the core HTTP request directly for piping it where you want:
|
||||
And then access the core HTTP request directly for piping:
|
||||
|
||||
```js
|
||||
app.post('/hello', (request, reply) => {
|
||||
@@ -225,19 +235,18 @@ fastify.route({
|
||||
})
|
||||
```
|
||||
|
||||
For piping file uploads you may want to check out [this
|
||||
plugin](https://github.com/fastify/fastify-multipart).
|
||||
For piping file uploads, check out
|
||||
[`@fastify/multipart`](https://github.com/fastify/fastify-multipart).
|
||||
|
||||
If you want the content type parser to be executed on all content types and not
|
||||
only on those that don't have a specific one, you should call the
|
||||
`removeAllContentTypeParsers` method first.
|
||||
To execute the content type parser on all content types, call
|
||||
`removeAllContentTypeParsers` first.
|
||||
|
||||
```js
|
||||
// Without this call, the request body with the content type application/json would be processed by the built-in JSON parser
|
||||
fastify.removeAllContentTypeParsers()
|
||||
|
||||
fastify.addContentTypeParser('*', function (request, payload, done) {
|
||||
var data = ''
|
||||
const data = ''
|
||||
payload.on('data', chunk => { data += chunk })
|
||||
payload.on('end', () => {
|
||||
done(null, data)
|
||||
|
||||
201
backend/node_modules/fastify/docs/Reference/Decorators.md
generated
vendored
201
backend/node_modules/fastify/docs/Reference/Decorators.md
generated
vendored
@@ -2,16 +2,15 @@
|
||||
|
||||
## Decorators
|
||||
|
||||
The decorators API allows customization of the core Fastify objects, such as the
|
||||
server instance itself and any request and reply objects used during the HTTP
|
||||
request lifecycle. The decorators API can be used to attach any type of property
|
||||
to the core objects, e.g. functions, plain objects, or native types.
|
||||
The decorators API customizes core Fastify objects, such as the server instance
|
||||
and any request and reply objects used during the HTTP request lifecycle. It
|
||||
can attach any type of property to core objects, e.g., functions, plain
|
||||
objects, or native types.
|
||||
|
||||
This API is *synchronous*. Attempting to define a decoration asynchronously
|
||||
could result in the Fastify instance booting before the decoration completes its
|
||||
initialization. To avoid this issue, and register an asynchronous decoration,
|
||||
the `register` API, in combination with `fastify-plugin`, must be used instead.
|
||||
To learn more, see the [Plugins](./Plugins.md) documentation.
|
||||
This API is *synchronous*. Defining a decoration asynchronously could result in
|
||||
the Fastify instance booting before the decoration completes. To register an
|
||||
asynchronous decoration, use the `register` API with `fastify-plugin`. See the
|
||||
[Plugins](./Plugins.md) documentation for more details.
|
||||
|
||||
Decorating core objects with this API allows the underlying JavaScript engine to
|
||||
optimize the handling of server, request, and reply objects. This is
|
||||
@@ -35,9 +34,9 @@ fastify.get('/', function (req, reply) {
|
||||
})
|
||||
```
|
||||
|
||||
Since the above example mutates the request object after it has already been
|
||||
instantiated, the JavaScript engine must deoptimize access to the request
|
||||
object. By using the decoration API this deoptimization is avoided:
|
||||
The above example mutates the request object after instantiation, causing the
|
||||
JavaScript engine to deoptimize access. Using the decoration API avoids this
|
||||
deoptimization:
|
||||
|
||||
```js
|
||||
// Decorate request with a 'user' property
|
||||
@@ -54,17 +53,13 @@ fastify.get('/', (req, reply) => {
|
||||
})
|
||||
```
|
||||
|
||||
Note that it is important to keep the initial shape of a decorated field as
|
||||
close as possible to the value intended to be set dynamically in the future.
|
||||
Initialize a decorator as a `''` if the intended value is a string, and as
|
||||
`null` if it will be an object or a function.
|
||||
|
||||
Remember this example works only with value types as reference types will be
|
||||
shared amongst all requests. See [decorateRequest](#decorate-request).
|
||||
|
||||
See [JavaScript engine fundamentals: Shapes and Inline
|
||||
Caches](https://mathiasbynens.be/notes/shapes-ics) for more information on this
|
||||
topic.
|
||||
Keep the initial shape of a decorated field close to its future dynamic value.
|
||||
Initialize a decorator as `''` for strings and `null` for objects or functions.
|
||||
This works only with value types; reference types will throw an error during
|
||||
Fastify startup. See [decorateRequest](#decorate-request) and
|
||||
[JavaScript engine fundamentals: Shapes
|
||||
and Inline Caches](https://mathiasbynens.be/notes/shapes-ics)
|
||||
for more information.
|
||||
|
||||
### Usage
|
||||
<a id="usage"></a>
|
||||
@@ -72,8 +67,7 @@ topic.
|
||||
#### `decorate(name, value, [dependencies])`
|
||||
<a id="decorate"></a>
|
||||
|
||||
This method is used to customize the Fastify [server](./Server.md)
|
||||
instance.
|
||||
This method customizes the Fastify [server](./Server.md) instance.
|
||||
|
||||
For example, to attach a new method to the server instance:
|
||||
|
||||
@@ -83,7 +77,7 @@ fastify.decorate('utility', function () {
|
||||
})
|
||||
```
|
||||
|
||||
As mentioned above, non-function values can be attached:
|
||||
Non-function values can also be attached to the server instance:
|
||||
|
||||
```js
|
||||
fastify.decorate('conf', {
|
||||
@@ -109,7 +103,7 @@ fastify.decorate('db', new DbConnection())
|
||||
fastify.get('/', async function (request, reply) {
|
||||
// using return
|
||||
return { hello: await this.db.query('world') }
|
||||
|
||||
|
||||
// or
|
||||
// using reply.send()
|
||||
reply.send({ hello: await this.db.query('world') })
|
||||
@@ -118,9 +112,9 @@ fastify.get('/', async function (request, reply) {
|
||||
```
|
||||
|
||||
The `dependencies` parameter is an optional list of decorators that the
|
||||
decorator being defined relies upon. This list is simply a list of string names
|
||||
of other decorators. In the following example, the "utility" decorator depends
|
||||
upon "greet" and "hi" decorators:
|
||||
decorator being defined relies upon. This list contains the names of other
|
||||
decorators. In the following example, the "utility" decorator depends on the
|
||||
"greet" and "hi" decorators:
|
||||
|
||||
```js
|
||||
async function greetDecorator (fastify, opts) {
|
||||
@@ -155,18 +149,17 @@ fastify.listen({ port: 3000 }, (err, address) => {
|
||||
})
|
||||
```
|
||||
|
||||
Note: using an arrow function will break the binding of `this` to the
|
||||
`FastifyInstance`.
|
||||
Using an arrow function breaks the binding of `this` to
|
||||
the `FastifyInstance`.
|
||||
|
||||
If a dependency is not satisfied, the `decorate` method will throw an exception.
|
||||
The dependency check is performed before the server instance is booted. Thus, it
|
||||
cannot occur during runtime.
|
||||
If a dependency is not satisfied, the `decorate` method throws an exception.
|
||||
The dependency check occurs before the server instance boots, not during
|
||||
runtime.
|
||||
|
||||
#### `decorateReply(name, value, [dependencies])`
|
||||
<a id="decorate-reply"></a>
|
||||
|
||||
As the name suggests, this API is used to add new methods/properties to the core
|
||||
`Reply` object:
|
||||
This API adds new methods/properties to the core `Reply` object:
|
||||
|
||||
```js
|
||||
fastify.decorateReply('utility', function () {
|
||||
@@ -174,28 +167,29 @@ fastify.decorateReply('utility', function () {
|
||||
})
|
||||
```
|
||||
|
||||
Note: using an arrow function will break the binding of `this` to the Fastify
|
||||
Using an arrow function will break the binding of `this` to the Fastify
|
||||
`Reply` instance.
|
||||
|
||||
Note: using `decorateReply` will emit a warning if used with a reference type:
|
||||
Using `decorateReply` will throw and error if used with a reference type:
|
||||
|
||||
```js
|
||||
// Don't do this
|
||||
fastify.decorateReply('foo', { bar: 'fizz'})
|
||||
```
|
||||
In this example, the reference of the object is shared with all the requests:
|
||||
In this example, the object reference would be shared with all requests, and
|
||||
**any mutation will impact all requests, potentially creating security
|
||||
vulnerabilities or memory leaks**. To achieve proper encapsulation across
|
||||
requests configure a new value for each incoming request in the [`'onRequest'`
|
||||
hook](./Hooks.md#onrequest). Example:
|
||||
vulnerabilities or memory leaks**. Fastify blocks this.
|
||||
|
||||
To achieve proper encapsulation across requests configure a new value for each
|
||||
incoming request in the [`'onRequest'` hook](./Hooks.md#onrequest).
|
||||
|
||||
```js
|
||||
const fp = require('fastify-plugin')
|
||||
|
||||
async function myPlugin (app) {
|
||||
app.decorateRequest('foo', null)
|
||||
app.decorateReply('foo')
|
||||
app.addHook('onRequest', async (req, reply) => {
|
||||
req.foo = { bar: 42 }
|
||||
reply.foo = { bar: 42 }
|
||||
})
|
||||
}
|
||||
|
||||
@@ -207,8 +201,8 @@ See [`decorate`](#decorate) for information about the `dependencies` parameter.
|
||||
#### `decorateRequest(name, value, [dependencies])`
|
||||
<a id="decorate-request"></a>
|
||||
|
||||
As above with [`decorateReply`](#decorate-reply), this API is used add new
|
||||
methods/properties to the core `Request` object:
|
||||
As with [`decorateReply`](#decorate-reply), this API adds new methods/properties
|
||||
to the core `Request` object:
|
||||
|
||||
```js
|
||||
fastify.decorateRequest('utility', function () {
|
||||
@@ -216,27 +210,29 @@ fastify.decorateRequest('utility', function () {
|
||||
})
|
||||
```
|
||||
|
||||
Note: using an arrow function will break the binding of `this` to the Fastify
|
||||
Using an arrow function will break the binding of `this` to the Fastify
|
||||
`Request` instance.
|
||||
|
||||
Note: using `decorateRequest` will emit a warning if used with a reference type:
|
||||
Using `decorateRequest` will emit an error if used with a reference type:
|
||||
|
||||
```js
|
||||
// Don't do this
|
||||
fastify.decorateRequest('foo', { bar: 'fizz'})
|
||||
```
|
||||
In this example, the reference of the object is shared with all the requests:
|
||||
In this example, the object reference would be shared with all requests, and
|
||||
**any mutation will impact all requests, potentially creating security
|
||||
vulnerabilities or memory leaks**.
|
||||
vulnerabilities or memory leaks**. Fastify blocks this.
|
||||
|
||||
To achieve proper encapsulation across requests configure a new value for each
|
||||
incoming request in the [`'onRequest'` hook](./Hooks.md#onrequest). Example:
|
||||
incoming request in the [`'onRequest'` hook](./Hooks.md#onrequest).
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
const fp = require('fastify-plugin')
|
||||
|
||||
async function myPlugin (app) {
|
||||
app.decorateRequest('foo', null)
|
||||
app.decorateRequest('foo')
|
||||
app.addHook('onRequest', async (req, reply) => {
|
||||
req.foo = { bar: 42 }
|
||||
})
|
||||
@@ -245,6 +241,28 @@ async function myPlugin (app) {
|
||||
module.exports = fp(myPlugin)
|
||||
```
|
||||
|
||||
The hook solution is more flexible and allows for more complex initialization
|
||||
because more logic can be added to the `onRequest` hook.
|
||||
|
||||
Another approach is to use the getter/setter pattern, but it requires 2 decorators:
|
||||
|
||||
```js
|
||||
fastify.decorateRequest('my_decorator_holder') // define the holder
|
||||
fastify.decorateRequest('user', {
|
||||
getter () {
|
||||
this.my_decorator_holder ??= {} // initialize the holder
|
||||
return this.my_decorator_holder
|
||||
}
|
||||
})
|
||||
|
||||
fastify.get('/', async function (req, reply) {
|
||||
req.user.access = 'granted'
|
||||
// other code
|
||||
})
|
||||
```
|
||||
|
||||
This ensures that the `user` property is always unique for each request.
|
||||
|
||||
See [`decorate`](#decorate) for information about the `dependencies` parameter.
|
||||
|
||||
#### `hasDecorator(name)`
|
||||
@@ -279,9 +297,7 @@ fastify.hasReplyDecorator('utility')
|
||||
|
||||
Defining a decorator (using `decorate`, `decorateRequest`, or `decorateReply`)
|
||||
with the same name more than once in the same **encapsulated** context will
|
||||
throw an exception.
|
||||
|
||||
As an example, the following will throw:
|
||||
throw an exception. For example, the following will throw:
|
||||
|
||||
```js
|
||||
const server = require('fastify')()
|
||||
@@ -332,9 +348,9 @@ server.listen({ port: 3000 })
|
||||
### Getters and Setters
|
||||
<a id="getters-setters"></a>
|
||||
|
||||
Decorators accept special "getter/setter" objects. These objects have functions
|
||||
named `getter` and `setter` (though the `setter` function is optional). This
|
||||
allows defining properties via decorators, for example:
|
||||
Decorators accept special "getter/setter" objects with `getter` and optional
|
||||
`setter` functions. This allows defining properties via decorators,
|
||||
for example:
|
||||
|
||||
```js
|
||||
fastify.decorate('foo', {
|
||||
@@ -349,3 +365,70 @@ Will define the `foo` property on the Fastify instance:
|
||||
```js
|
||||
console.log(fastify.foo) // 'a getter'
|
||||
```
|
||||
|
||||
#### `getDecorator(name)`
|
||||
<a id="get-decorator"></a>
|
||||
|
||||
Used to retrieve an existing decorator from the Fastify instance, `Request`,
|
||||
or `Reply`.
|
||||
If the decorator is not defined, an `FST_ERR_DEC_UNDECLARED` error is thrown.
|
||||
|
||||
```js
|
||||
// Get a decorator from the Fastify instance
|
||||
const utility = fastify.getDecorator('utility')
|
||||
|
||||
// Get a decorator from the request object
|
||||
const user = request.getDecorator('user')
|
||||
|
||||
// Get a decorator from the reply object
|
||||
const helper = reply.getDecorator('helper')
|
||||
```
|
||||
|
||||
The `getDecorator` method is useful for dependency validation - it can be used to
|
||||
check for required decorators at registration time. If any are missing, it fails
|
||||
at boot, ensuring dependencies are available during the request lifecycle.
|
||||
|
||||
```js
|
||||
fastify.register(async function (fastify) {
|
||||
// Verify the decorator exists before using it
|
||||
const usersRepository = fastify.getDecorator('usersRepository')
|
||||
|
||||
fastify.get('/users', async function (request, reply) {
|
||||
return usersRepository.findAll()
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
> ℹ️ Note: For TypeScript users, `getDecorator` supports generic type parameters.
|
||||
> See the [TypeScript documentation](/docs/Reference/TypeScript.md) for
|
||||
> advanced typing examples.
|
||||
|
||||
#### `setDecorator(name, value)`
|
||||
<a id="set-decorator"></a>
|
||||
|
||||
Used to safely update the value of a `Request` decorator.
|
||||
If the decorator does not exist, a `FST_ERR_DEC_UNDECLARED` error is thrown.
|
||||
|
||||
```js
|
||||
fastify.decorateRequest('user', null)
|
||||
|
||||
fastify.addHook('preHandler', async (req, reply) => {
|
||||
// Safely set the decorator value
|
||||
req.setDecorator('user', 'Bob Dylan')
|
||||
})
|
||||
```
|
||||
|
||||
The `setDecorator` method provides runtime safety by ensuring the decorator exists
|
||||
before setting its value, preventing errors from typos in decorator names.
|
||||
|
||||
```js
|
||||
fastify.decorateRequest('account', null)
|
||||
fastify.addHook('preHandler', async (req, reply) => {
|
||||
// This will throw FST_ERR_DEC_UNDECLARED due to typo in decorator name
|
||||
req.setDecorator('acount', { id: 123 })
|
||||
})
|
||||
```
|
||||
|
||||
> ℹ️ Note: For TypeScript users, see the
|
||||
> [TypeScript documentation](/docs/Reference/TypeScript.md) for advanced
|
||||
> typing examples using `setDecorator<T>`.
|
||||
|
||||
65
backend/node_modules/fastify/docs/Reference/Encapsulation.md
generated
vendored
65
backend/node_modules/fastify/docs/Reference/Encapsulation.md
generated
vendored
@@ -3,21 +3,20 @@
|
||||
## Encapsulation
|
||||
<a id="encapsulation"></a>
|
||||
|
||||
A fundamental feature of Fastify is the "encapsulation context." The
|
||||
encapsulation context governs which [decorators](./Decorators.md), registered
|
||||
[hooks](./Hooks.md), and [plugins](./Plugins.md) are available to
|
||||
[routes](./Routes.md). A visual representation of the encapsulation context
|
||||
is shown in the following figure:
|
||||
A fundamental feature of Fastify is the "encapsulation context." It governs
|
||||
which [decorators](./Decorators.md), registered [hooks](./Hooks.md), and
|
||||
[plugins](./Plugins.md) are available to [routes](./Routes.md). A visual
|
||||
representation of the encapsulation context is shown in the following figure:
|
||||
|
||||

|
||||
|
||||
In the above figure, there are several entities:
|
||||
In the figure above, there are several entities:
|
||||
|
||||
1. The _root context_
|
||||
2. Three _root plugins_
|
||||
3. Two _child contexts_ where each _child context_ has
|
||||
3. Two _child contexts_, each with:
|
||||
* Two _child plugins_
|
||||
* One _grandchild context_ where each _grandchild context_ has
|
||||
* One _grandchild context_, each with:
|
||||
- Three _child plugins_
|
||||
|
||||
Every _child context_ and _grandchild context_ has access to the _root plugins_.
|
||||
@@ -26,15 +25,18 @@ _child plugins_ registered within the containing _child context_, but the
|
||||
containing _child context_ **does not** have access to the _child plugins_
|
||||
registered within its _grandchild context_.
|
||||
|
||||
Given that everything in Fastify is a [plugin](./Plugins.md), except for the
|
||||
Given that everything in Fastify is a [plugin](./Plugins.md) except for the
|
||||
_root context_, every "context" and "plugin" in this example is a plugin
|
||||
that can consist of decorators, hooks, plugins, and routes. Thus, to put
|
||||
this example into concrete terms, consider a basic scenario of a REST API
|
||||
server that has three routes: the first route (`/one`) requires authentication,
|
||||
the second route (`/two`) does not, and the third route (`/three`) has
|
||||
access to the same context as the second route. Using
|
||||
[@fastify/bearer-auth][bearer] to provide the authentication, the code for this
|
||||
example is as follows:
|
||||
that can consist of decorators, hooks, plugins, and routes. As plugins, they
|
||||
must still signal completion either by returning a Promise (e.g., using `async`
|
||||
functions) or by calling the `done` function if using the callback style.
|
||||
|
||||
To put this
|
||||
example into concrete terms, consider a basic scenario of a REST API server
|
||||
with three routes: the first route (`/one`) requires authentication, the
|
||||
second route (`/two`) does not, and the third route (`/three`) has access to
|
||||
the same context as the second route. Using [@fastify/bearer-auth][bearer] to
|
||||
provide authentication, the code for this example is as follows:
|
||||
|
||||
```js
|
||||
'use strict'
|
||||
@@ -52,9 +54,9 @@ fastify.register(async function authenticatedContext (childServer) {
|
||||
handler (request, response) {
|
||||
response.send({
|
||||
answer: request.answer,
|
||||
// request.foo will be undefined as it's only defined in publicContext
|
||||
// request.foo will be undefined as it is only defined in publicContext
|
||||
foo: request.foo,
|
||||
// request.bar will be undefined as it's only defined in grandchildContext
|
||||
// request.bar will be undefined as it is only defined in grandchildContext
|
||||
bar: request.bar
|
||||
})
|
||||
}
|
||||
@@ -71,7 +73,7 @@ fastify.register(async function publicContext (childServer) {
|
||||
response.send({
|
||||
answer: request.answer,
|
||||
foo: request.foo,
|
||||
// request.bar will be undefined as it's only defined in grandchildContext
|
||||
// request.bar will be undefined as it is only defined in grandchildContext
|
||||
bar: request.bar
|
||||
})
|
||||
}
|
||||
@@ -97,16 +99,16 @@ fastify.register(async function publicContext (childServer) {
|
||||
fastify.listen({ port: 8000 })
|
||||
```
|
||||
|
||||
The above server example shows all of the encapsulation concepts outlined in the
|
||||
The server example above demonstrates the encapsulation concepts from the
|
||||
original diagram:
|
||||
|
||||
1. Each _child context_ (`authenticatedContext`, `publicContext`, and
|
||||
`grandchildContext`) has access to the `answer` request decorator defined in
|
||||
the _root context_.
|
||||
`grandchildContext`) has access to the `answer` request decorator defined in
|
||||
the _root context_.
|
||||
2. Only the `authenticatedContext` has access to the `@fastify/bearer-auth`
|
||||
plugin.
|
||||
plugin.
|
||||
3. Both the `publicContext` and `grandchildContext` have access to the `foo`
|
||||
request decorator.
|
||||
request decorator.
|
||||
4. Only the `grandchildContext` has access to the `bar` request decorator.
|
||||
|
||||
To see this, start the server and issue requests:
|
||||
@@ -125,16 +127,13 @@ To see this, start the server and issue requests:
|
||||
## Sharing Between Contexts
|
||||
<a id="shared-context"></a>
|
||||
|
||||
Notice that each context in the prior example inherits _only_ from the parent
|
||||
contexts. Parent contexts cannot access any entities within their descendent
|
||||
contexts. This default is occasionally not desired. In such cases, the
|
||||
encapsulation context can be broken through the usage of
|
||||
[fastify-plugin][fastify-plugin] such that anything registered in a descendent
|
||||
context is available to the containing parent context.
|
||||
Each context in the prior example inherits _only_ from its parent contexts. Parent
|
||||
contexts cannot access entities within their descendant contexts. If needed,
|
||||
encapsulation can be broken using [fastify-plugin][fastify-plugin], making
|
||||
anything registered in a descendant context available to the parent context.
|
||||
|
||||
Assuming the `publicContext` needs access to the `bar` decorator defined
|
||||
within the `grandchildContext` in the previous example, the code can be
|
||||
rewritten as:
|
||||
To allow `publicContext` access to the `bar` decorator in `grandchildContext`,
|
||||
rewrite the code as follows:
|
||||
|
||||
```js
|
||||
'use strict'
|
||||
|
||||
125
backend/node_modules/fastify/docs/Reference/Errors.md
generated
vendored
125
backend/node_modules/fastify/docs/Reference/Errors.md
generated
vendored
@@ -5,7 +5,7 @@
|
||||
|
||||
**Table of contents**
|
||||
- [Errors](#errors)
|
||||
- [Error Handling In Node.js](#error-handling-in-node.js)
|
||||
- [Error Handling In Node.js](#error-handling-in-nodejs)
|
||||
- [Uncaught Errors](#uncaught-errors)
|
||||
- [Catching Errors In Promises](#catching-errors-in-promises)
|
||||
- [Errors In Fastify](#errors-in-fastify)
|
||||
@@ -20,7 +20,6 @@
|
||||
- [FST_ERR_SCHEMA_ERROR_FORMATTER_NOT_FN](#fst_err_schema_error_formatter_not_fn)
|
||||
- [FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_OBJ](#fst_err_ajv_custom_options_opt_not_obj)
|
||||
- [FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_ARR](#fst_err_ajv_custom_options_opt_not_arr)
|
||||
- [FST_ERR_VERSION_CONSTRAINT_NOT_STR](#fst_err_version_constraint_not_str)
|
||||
- [FST_ERR_CTP_ALREADY_PRESENT](#fst_err_ctp_already_present)
|
||||
- [FST_ERR_CTP_INVALID_TYPE](#fst_err_ctp_invalid_type)
|
||||
- [FST_ERR_CTP_EMPTY_TYPE](#fst_err_ctp_empty_type)
|
||||
@@ -30,12 +29,15 @@
|
||||
- [FST_ERR_CTP_INVALID_MEDIA_TYPE](#fst_err_ctp_invalid_media_type)
|
||||
- [FST_ERR_CTP_INVALID_CONTENT_LENGTH](#fst_err_ctp_invalid_content_length)
|
||||
- [FST_ERR_CTP_EMPTY_JSON_BODY](#fst_err_ctp_empty_json_body)
|
||||
- [FST_ERR_CTP_INVALID_JSON_BODY](#fst_err_ctp_invalid_json_body)
|
||||
- [FST_ERR_CTP_INSTANCE_ALREADY_STARTED](#fst_err_ctp_instance_already_started)
|
||||
- [FST_ERR_INSTANCE_ALREADY_LISTENING](#fst_err_instance_already_listening)
|
||||
- [FST_ERR_DEC_ALREADY_PRESENT](#fst_err_dec_already_present)
|
||||
- [FST_ERR_DEC_DEPENDENCY_INVALID_TYPE](#fst_err_dec_dependency_invalid_type)
|
||||
- [FST_ERR_DEC_MISSING_DEPENDENCY](#fst_err_dec_missing_dependency)
|
||||
- [FST_ERR_DEC_AFTER_START](#fst_err_dec_after_start)
|
||||
- [FST_ERR_DEC_REFERENCE_TYPE](#fst_err_dec_reference_type)
|
||||
- [FST_ERR_DEC_UNDECLARED](#fst_err_dec_undeclared)
|
||||
- [FST_ERR_HOOK_INVALID_TYPE](#fst_err_hook_invalid_type)
|
||||
- [FST_ERR_HOOK_INVALID_HANDLER](#fst_err_hook_invalid_handler)
|
||||
- [FST_ERR_HOOK_INVALID_ASYNC_HANDLER](#fst_err_hook_invalid_async_handler)
|
||||
@@ -44,8 +46,12 @@
|
||||
- [FST_ERR_HOOK_TIMEOUT](#fst_err_hook_timeout)
|
||||
- [FST_ERR_LOG_INVALID_DESTINATION](#fst_err_log_invalid_destination)
|
||||
- [FST_ERR_LOG_INVALID_LOGGER](#fst_err_log_invalid_logger)
|
||||
- [FST_ERR_LOG_INVALID_LOGGER_INSTANCE](#fst_err_log_invalid_logger_instance)
|
||||
- [FST_ERR_LOG_INVALID_LOGGER_CONFIG](#fst_err_log_invalid_logger_config)
|
||||
- [FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED](#fst_err_log_logger_and_logger_instance_provided)
|
||||
- [FST_ERR_REP_INVALID_PAYLOAD_TYPE](#fst_err_rep_invalid_payload_type)
|
||||
- [FST_ERR_REP_RESPONSE_BODY_CONSUMED](#fst_err_rep_response_body_consumed)
|
||||
- [FST_ERR_REP_READABLE_STREAM_LOCKED](#fst_err_rep_readable_stream_locked)
|
||||
- [FST_ERR_REP_ALREADY_SENT](#fst_err_rep_already_sent)
|
||||
- [FST_ERR_REP_SENT_VALUE](#fst_err_rep_sent_value)
|
||||
- [FST_ERR_SEND_INSIDE_ONERR](#fst_err_send_inside_onerr)
|
||||
@@ -64,13 +70,11 @@
|
||||
- [FST_ERR_SCH_VALIDATION_BUILD](#fst_err_sch_validation_build)
|
||||
- [FST_ERR_SCH_SERIALIZATION_BUILD](#fst_err_sch_serialization_build)
|
||||
- [FST_ERR_SCH_RESPONSE_SCHEMA_NOT_NESTED_2XX](#fst_err_sch_response_schema_not_nested_2xx)
|
||||
- [FST_ERR_HTTP2_INVALID_VERSION](#fst_err_http2_invalid_version)
|
||||
- [FST_ERR_INIT_OPTS_INVALID](#fst_err_init_opts_invalid)
|
||||
- [FST_ERR_FORCE_CLOSE_CONNECTIONS_IDLE_NOT_AVAILABLE](#fst_err_force_close_connections_idle_not_available)
|
||||
- [FST_ERR_DUPLICATED_ROUTE](#fst_err_duplicated_route)
|
||||
- [FST_ERR_BAD_URL](#fst_err_bad_url)
|
||||
- [FST_ERR_ASYNC_CONSTRAINT](#fst_err_async_constraint)
|
||||
- [FST_ERR_DEFAULT_ROUTE_INVALID_TYPE](#fst_err_default_route_invalid_type)
|
||||
- [FST_ERR_INVALID_URL](#fst_err_invalid_url)
|
||||
- [FST_ERR_ROUTE_OPTIONS_NOT_OBJ](#fst_err_route_options_not_obj)
|
||||
- [FST_ERR_ROUTE_DUPLICATED_HANDLER](#fst_err_route_duplicated_handler)
|
||||
@@ -90,16 +94,18 @@
|
||||
- [FST_ERR_PARENT_PLUGIN_BOOTED](#fst_err_parent_plugin_booted)
|
||||
- [FST_ERR_PLUGIN_TIMEOUT](#fst_err_plugin_timeout)
|
||||
- [FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE](#fst_err_plugin_not_present_in_instance)
|
||||
- [FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER](#fst_err_plugin_invalid_async_handler)
|
||||
- [FST_ERR_VALIDATION](#fst_err_validation)
|
||||
- [FST_ERR_LISTEN_OPTIONS_INVALID](#fst_err_listen_options_invalid)
|
||||
- [FST_ERR_ERROR_HANDLER_NOT_FN](#fst_err_error_handler_not_fn)
|
||||
- [FST_ERR_ERROR_HANDLER_ALREADY_SET](#fst_err_error_handler_already_set)
|
||||
|
||||
### Error Handling In Node.js
|
||||
<a id="error-handling"></a>
|
||||
|
||||
#### Uncaught Errors
|
||||
In Node.js, uncaught errors are likely to cause memory leaks, file descriptor
|
||||
leaks, and other major production issues.
|
||||
In Node.js, uncaught errors can cause memory leaks, file descriptor leaks, and
|
||||
other major production issues.
|
||||
[Domains](https://nodejs.org/en/docs/guides/domain-postmortem/) were a failed
|
||||
attempt to fix this.
|
||||
|
||||
@@ -108,29 +114,28 @@ way to deal with them is to
|
||||
[crash](https://nodejs.org/api/process.html#process_warning_using_uncaughtexception_correctly).
|
||||
|
||||
#### Catching Errors In Promises
|
||||
If you are using promises, you should attach a `.catch()` handler synchronously.
|
||||
When using promises, attach a `.catch()` handler synchronously.
|
||||
|
||||
### Errors In Fastify
|
||||
Fastify follows an all-or-nothing approach and aims to be lean and optimal as
|
||||
much as possible. The developer is responsible for making sure that the errors
|
||||
are handled properly.
|
||||
Fastify follows an all-or-nothing approach and aims to be lean and optimal. The
|
||||
developer is responsible for ensuring errors are handled properly.
|
||||
|
||||
#### Errors In Input Data
|
||||
Most errors are a result of unexpected input data, so we recommend [validating
|
||||
your input data against a JSON schema](./Validation-and-Serialization.md).
|
||||
Most errors result from unexpected input data, so it is recommended to
|
||||
[validate input data against a JSON schema](./Validation-and-Serialization.md).
|
||||
|
||||
#### Catching Uncaught Errors In Fastify
|
||||
Fastify tries to catch as many uncaught errors as it can without hindering
|
||||
Fastify tries to catch as many uncaught errors as possible without hindering
|
||||
performance. This includes:
|
||||
|
||||
1. synchronous routes, e.g. `app.get('/', () => { throw new Error('kaboom') })`
|
||||
2. `async` routes, e.g. `app.get('/', async () => { throw new Error('kaboom')
|
||||
})`
|
||||
|
||||
The error in both cases will be caught safely and routed to Fastify's default
|
||||
error handler for a generic `500 Internal Server Error` response.
|
||||
In both cases, the error will be caught safely and routed to Fastify's default
|
||||
error handler, resulting in a generic `500 Internal Server Error` response.
|
||||
|
||||
To customize this behavior you should use
|
||||
To customize this behavior, use
|
||||
[`setErrorHandler`](./Server.md#seterrorhandler).
|
||||
|
||||
### Errors In Fastify Lifecycle Hooks And A Custom Error Handler
|
||||
@@ -140,52 +145,50 @@ From the [Hooks documentation](./Hooks.md#manage-errors-from-a-hook):
|
||||
> `done()` and Fastify will automatically close the request and send the
|
||||
> appropriate error code to the user.
|
||||
|
||||
When a custom error handler has been defined through
|
||||
[`setErrorHandler`](./Server.md#seterrorhandler), the custom error handler will
|
||||
receive the error passed to the `done()` callback (or through other supported
|
||||
automatic error handling mechanisms). If `setErrorHandler` has been used
|
||||
multiple times to define multiple handlers, the error will be routed to the most
|
||||
precedent handler defined within the error [encapsulation
|
||||
context](./Encapsulation.md). Error handlers are fully encapsulated, so a
|
||||
`setErrorHandler` call within a plugin will limit the error handler to that
|
||||
plugin's context.
|
||||
When a custom error handler is defined through
|
||||
[`setErrorHandler`](./Server.md#seterrorhandler), it will receive the error
|
||||
passed to the `done()` callback or through other supported automatic error
|
||||
handling mechanisms. If `setErrorHandler` is used multiple times, the error will
|
||||
be routed to the most precedent handler within the error
|
||||
[encapsulation context](./Encapsulation.md). Error handlers are fully
|
||||
encapsulated, so a `setErrorHandler` call within a plugin will limit the error
|
||||
handler to that plugin's context.
|
||||
|
||||
The root error handler is Fastify's generic error handler. This error handler
|
||||
will use the headers and status code in the `Error` object, if they exist. The
|
||||
headers and status code will not be automatically set if a custom error handler
|
||||
is provided.
|
||||
|
||||
Some things to consider in your custom error handler:
|
||||
The following should be considered when using a custom error handler:
|
||||
|
||||
- you can `reply.send(data)`, which will behave as it would in [regular route
|
||||
handlers](./Reply.md#senddata)
|
||||
- `reply.send(data)` behaves as in [regular route handlers](./Reply.md#senddata)
|
||||
- objects are serialized, triggering the `preSerialization` lifecycle hook if
|
||||
you have one defined
|
||||
- strings, buffers, and streams are sent to the client, with appropriate
|
||||
headers (no serialization)
|
||||
defined
|
||||
- strings, buffers, and streams are sent to the client with appropriate headers
|
||||
(no serialization)
|
||||
|
||||
- You can throw a new error in your custom error handler - errors (new error or
|
||||
the received error parameter re-thrown) - will call the parent `errorHandler`.
|
||||
- `onError` hook will be triggered once only for the first error being thrown.
|
||||
- an error will not be triggered twice from a lifecycle hook - Fastify
|
||||
internally monitors the error invocation to avoid infinite loops for errors
|
||||
thrown in the reply phases of the lifecycle. (those after the route handler)
|
||||
- Throwing a new error in a custom error handler will call the parent
|
||||
`errorHandler`.
|
||||
- The `onError` hook will be triggered once for the first error thrown
|
||||
- An error will not be triggered twice from a lifecycle hook. Fastify
|
||||
internally monitors error invocation to avoid infinite loops for errors
|
||||
thrown in the reply phases of the lifecycle (those after the route handler)
|
||||
|
||||
When utilizing Fastify's custom error handling through [`setErrorHandler`](./Server.md#seterrorhandler),
|
||||
you should be aware of how errors are propagated between custom and default
|
||||
error handlers.
|
||||
When using Fastify's custom error handling through
|
||||
[`setErrorHandler`](./Server.md#seterrorhandler), be aware of how errors are
|
||||
propagated between custom and default error handlers.
|
||||
|
||||
If a plugin's error handler re-throws an error, and the error is not an
|
||||
instance of [Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)
|
||||
(as seen in the `/bad` route in the following example), it will not propagate
|
||||
to the parent context error handler. Instead, it will be caught by the default
|
||||
error handler.
|
||||
If a plugin's error handler re-throws an error that is not an instance of
|
||||
[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error),
|
||||
it will not propagate to the parent context error handler. Instead, it will be
|
||||
caught by the default error handler. This can be seen in the `/bad` route of the
|
||||
example below.
|
||||
|
||||
To ensure consistent error handling, it is recommended to throw instances of
|
||||
`Error`. For instance, in the following example, replacing `throw 'foo'` with
|
||||
`throw new Error('foo')` in the `/bad` route ensures that errors propagate through
|
||||
the custom error handling chain as intended. This practice helps avoid potential
|
||||
pitfalls when working with custom error handling in Fastify.
|
||||
To ensure consistent error handling, throw instances of `Error`. For example,
|
||||
replace `throw 'foo'` with `throw new Error('foo')` in the `/bad` route to
|
||||
ensure errors propagate through the custom error handling chain as intended.
|
||||
This practice helps avoid potential pitfalls when working with custom error
|
||||
handling in Fastify.
|
||||
|
||||
For example:
|
||||
```js
|
||||
@@ -238,7 +241,7 @@ You can access `errorCodes` for mapping:
|
||||
// ESM
|
||||
import { errorCodes } from 'fastify'
|
||||
|
||||
// CommonJs
|
||||
// CommonJS
|
||||
const errorCodes = require('fastify').errorCodes
|
||||
```
|
||||
|
||||
@@ -263,7 +266,7 @@ fastify.setErrorHandler(function (error, request, reply) {
|
||||
// Send error response
|
||||
reply.status(500).send({ ok: false })
|
||||
} else {
|
||||
// fastify will use parent error handler to handle this
|
||||
// Fastify will use parent error handler to handle this
|
||||
reply.send(error)
|
||||
}
|
||||
})
|
||||
@@ -278,7 +281,7 @@ fastify.listen({ port: 3000 }, function (err, address) {
|
||||
})
|
||||
```
|
||||
|
||||
Below is a table with all the error codes that Fastify uses.
|
||||
Below is a table with all the error codes used by Fastify.
|
||||
|
||||
| Code | Description | How to solve | Discussion |
|
||||
|------|-------------|--------------|------------|
|
||||
@@ -289,7 +292,6 @@ Below is a table with all the error codes that Fastify uses.
|
||||
| <a id="fst_err_schema_error_formatter_not_fn">FST_ERR_SCHEMA_ERROR_FORMATTER_NOT_FN</a> | SchemaErrorFormatter option wrongly specified. | SchemaErrorFormatter option should be a non async function. | [#4554](https://github.com/fastify/fastify/pull/4554) |
|
||||
| <a id="fst_err_ajv_custom_options_opt_not_obj">FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_OBJ</a> | ajv.customOptions wrongly specified. | ajv.customOptions option should be an object. | [#4554](https://github.com/fastify/fastify/pull/4554) |
|
||||
| <a id="fst_err_ajv_custom_options_opt_not_arr">FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_ARR</a> | ajv.plugins option wrongly specified. | ajv.plugins option should be an array. | [#4554](https://github.com/fastify/fastify/pull/4554) |
|
||||
| <a id="fst_err_version_constraint_not_str">FST_ERR_VERSION_CONSTRAINT_NOT_STR</a> | Version constraint wrongly specified. | Version constraint should be a string. | [#4554](https://github.com/fastify/fastify/pull/4554) |
|
||||
| <a id="fst_err_ctp_already_present">FST_ERR_CTP_ALREADY_PRESENT</a> | The parser for this content type was already registered. | Use a different content type or delete the already registered parser. | [#1168](https://github.com/fastify/fastify/pull/1168) |
|
||||
| <a id="fst_err_ctp_invalid_type">FST_ERR_CTP_INVALID_TYPE</a> | `Content-Type` wrongly specified | The `Content-Type` should be a string. | [#1168](https://github.com/fastify/fastify/pull/1168) |
|
||||
| <a id="fst_err_ctp_empty_type">FST_ERR_CTP_EMPTY_TYPE</a> | `Content-Type` is an empty string. | `Content-Type` cannot be an empty string. | [#1168](https://github.com/fastify/fastify/pull/1168) |
|
||||
@@ -298,13 +300,16 @@ Below is a table with all the error codes that Fastify uses.
|
||||
| <a id="fst_err_ctp_body_too_large">FST_ERR_CTP_BODY_TOO_LARGE</a> | The request body is larger than the provided limit. | Increase the limit in the Fastify server instance setting: [bodyLimit](./Server.md#bodylimit) | [#1168](https://github.com/fastify/fastify/pull/1168) |
|
||||
| <a id="fst_err_ctp_invalid_media_type">FST_ERR_CTP_INVALID_MEDIA_TYPE</a> | The received media type is not supported (i.e. there is no suitable `Content-Type` parser for it). | Use a different content type. | [#1168](https://github.com/fastify/fastify/pull/1168) |
|
||||
| <a id="fst_err_ctp_invalid_content_length">FST_ERR_CTP_INVALID_CONTENT_LENGTH</a> | Request body size did not match <code>Content-Length</code>. | Check the request body size and the <code>Content-Length</code> header. | [#1168](https://github.com/fastify/fastify/pull/1168) |
|
||||
| <a id="fst_err_ctp_empty_json_body">FST_ERR_CTP_EMPTY_JSON_BODY</a> | Body cannot be empty when content-type is set to <code>application/json</code>. | Check the request body. | [#1253](https://github.com/fastify/fastify/pull/1253) |
|
||||
| <a id="fst_err_ctp_empty_json_body">FST_ERR_CTP_EMPTY_JSON_BODY</a> | Body is not valid JSON but content-type is set to <code>application/json</code>. | Check if the request body is valid JSON. | [#5925](https://github.com/fastify/fastify/pull/5925) |
|
||||
| <a id="fst_err_ctp_invalid_json_body">FST_ERR_CTP_INVALID_JSON_BODY</a> | Body cannot be empty when content-type is set to <code>application/json</code>. | Check the request body. | [#1253](https://github.com/fastify/fastify/pull/1253) |
|
||||
| <a id="fst_err_ctp_instance_already_started">FST_ERR_CTP_INSTANCE_ALREADY_STARTED</a> | Fastify is already started. | - | [#4554](https://github.com/fastify/fastify/pull/4554) |
|
||||
| <a id="fst_err_instance_already_listening">FST_ERR_INSTANCE_ALREADY_LISTENING</a> | Fastify instance is already listening. | - | [#4554](https://github.com/fastify/fastify/pull/4554) |
|
||||
| <a id="fst_err_dec_already_present">FST_ERR_DEC_ALREADY_PRESENT</a> | A decorator with the same name is already registered. | Use a different decorator name. | [#1168](https://github.com/fastify/fastify/pull/1168) |
|
||||
| <a id="fst_err_dec_dependency_invalid_type">FST_ERR_DEC_DEPENDENCY_INVALID_TYPE</a> | The dependencies of decorator must be of type `Array`. | Use an array for the dependencies. | [#3090](https://github.com/fastify/fastify/pull/3090) |
|
||||
| <a id="fst_err_dec_missing_dependency">FST_ERR_DEC_MISSING_DEPENDENCY</a> | The decorator cannot be registered due to a missing dependency. | Register the missing dependency. | [#1168](https://github.com/fastify/fastify/pull/1168) |
|
||||
| <a id="fst_err_dec_after_start">FST_ERR_DEC_AFTER_START</a> | The decorator cannot be added after start. | Add the decorator before starting the server. | [#2128](https://github.com/fastify/fastify/pull/2128) |
|
||||
| <a id="fst_err_dec_reference_type">FST_ERR_DEC_REFERENCE_TYPE</a> | The decorator cannot be a reference type. | Define the decorator with a getter/setter interface or an empty decorator with a hook. | [#5462](https://github.com/fastify/fastify/pull/5462) |
|
||||
| <a id="fst_err_dec_undeclared">FST_ERR_DEC_UNDECLARED</a> | An attempt was made to access a decorator that has not been declared. | Declare the decorator before using it. | [#](https://github.com/fastify/fastify/pull/)
|
||||
| <a id="fst_err_hook_invalid_type">FST_ERR_HOOK_INVALID_TYPE</a> | The hook name must be a string. | Use a string for the hook name. | [#1168](https://github.com/fastify/fastify/pull/1168) |
|
||||
| <a id="fst_err_hook_invalid_handler">FST_ERR_HOOK_INVALID_HANDLER</a> | The hook callback must be a function. | Use a function for the hook callback. | [#1168](https://github.com/fastify/fastify/pull/1168) |
|
||||
| <a id="fst_err_hook_invalid_async_handler">FST_ERR_HOOK_INVALID_ASYNC_HANDLER</a> | Async function has too many arguments. Async hooks should not use the `done` argument. | Remove the `done` argument from the async hook. | [#4367](https://github.com/fastify/fastify/pull/4367) |
|
||||
@@ -313,8 +318,12 @@ Below is a table with all the error codes that Fastify uses.
|
||||
| <a id="fst_err_hook_timeout">FST_ERR_HOOK_TIMEOUT</a> | A callback for a hook timed out. | Increase the timeout for the hook. | [#3106](https://github.com/fastify/fastify/pull/3106) |
|
||||
| <a id="fst_err_log_invalid_destination">FST_ERR_LOG_INVALID_DESTINATION</a> | The logger does not accept the specified destination. | Use a `'stream'` or a `'file'` as the destination. | [#1168](https://github.com/fastify/fastify/pull/1168) |
|
||||
| <a id="fst_err_log_invalid_logger">FST_ERR_LOG_INVALID_LOGGER</a> | The logger should have all these methods: `'info'`, `'error'`, `'debug'`, `'fatal'`, `'warn'`, `'trace'`, `'child'`. | Use a logger with all the required methods. | [#4520](https://github.com/fastify/fastify/pull/4520) |
|
||||
| <a id="fst_err_log_invalid_logger_instance">FST_ERR_LOG_INVALID_LOGGER_INSTANCE</a> | The `loggerInstance` only accepts a logger instance, not a configuration object. | To pass a configuration object, use `'logger'` instead. | [#5020](https://github.com/fastify/fastify/pull/5020) |
|
||||
| <a id="fst_err_log_invalid_logger_config">FST_ERR_LOG_INVALID_LOGGER_CONFIG</a> | The logger option only accepts a configuration object, not a logger instance. | To pass an instance, use `'loggerInstance'` instead. | [#5020](https://github.com/fastify/fastify/pull/5020) |
|
||||
| <a id="fst_err_log_logger_and_logger_instance_provided">FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED</a> | You cannot provide both `'logger'` and `'loggerInstance'`. | Please provide only one option. | [#5020](https://github.com/fastify/fastify/pull/5020) |
|
||||
| <a id="fst_err_rep_invalid_payload_type">FST_ERR_REP_INVALID_PAYLOAD_TYPE</a> | Reply payload can be either a `string` or a `Buffer`. | Use a `string` or a `Buffer` for the payload. | [#1168](https://github.com/fastify/fastify/pull/1168) |
|
||||
| <a id="fst_err_rep_response_body_consumed">FST_ERR_REP_RESPONSE_BODY_CONSUMED</a> | Using `Response` as reply payload, but the body is being consumed. | Make sure you don't consume the `Response.body` | [#5286](https://github.com/fastify/fastify/pull/5286) |
|
||||
| <a id="fst_err_rep_readable_stream_locked">FST_ERR_REP_READABLE_STREAM_LOCKED</a> | Using `ReadableStream` as reply payload, but locked with another reader. | Make sure you don't call the `Readable.getReader` before sending or release lock with `reader.releaseLock()` before sending. | [#5920](https://github.com/fastify/fastify/pull/5920) |
|
||||
| <a id="fst_err_rep_already_sent">FST_ERR_REP_ALREADY_SENT</a> | A response was already sent. | - | [#1336](https://github.com/fastify/fastify/pull/1336) |
|
||||
| <a id="fst_err_rep_sent_value">FST_ERR_REP_SENT_VALUE</a> | The only possible value for `reply.sent` is `true`. | - | [#1336](https://github.com/fastify/fastify/pull/1336) |
|
||||
| <a id="fst_err_send_inside_onerr">FST_ERR_SEND_INSIDE_ONERR</a> | You cannot use `send` inside the `onError` hook. | - | [#1348](https://github.com/fastify/fastify/pull/1348) |
|
||||
@@ -333,13 +342,11 @@ Below is a table with all the error codes that Fastify uses.
|
||||
| <a id="fst_err_sch_validation_build">FST_ERR_SCH_VALIDATION_BUILD</a> | The JSON schema provided for validation to a route is not valid. | Fix the JSON schema. | [#2023](https://github.com/fastify/fastify/pull/2023) |
|
||||
| <a id="fst_err_sch_serialization_build">FST_ERR_SCH_SERIALIZATION_BUILD</a> | The JSON schema provided for serialization of a route response is not valid. | Fix the JSON schema. | [#2023](https://github.com/fastify/fastify/pull/2023) |
|
||||
| <a id="fst_err_sch_response_schema_not_nested_2xx">FST_ERR_SCH_RESPONSE_SCHEMA_NOT_NESTED_2XX</a> | Response schemas should be nested under a valid status code (2XX). | Use a valid status code. | [#4554](https://github.com/fastify/fastify/pull/4554) |
|
||||
| <a id="fst_err_http2_invalid_version">FST_ERR_HTTP2_INVALID_VERSION</a> | HTTP2 is available only from node >= 8.8.1. | Use a higher version of node. | [#1346](https://github.com/fastify/fastify/pull/1346) |
|
||||
| <a id="fst_err_init_opts_invalid">FST_ERR_INIT_OPTS_INVALID</a> | Invalid initialization options. | Use valid initialization options. | [#1471](https://github.com/fastify/fastify/pull/1471) |
|
||||
| <a id="fst_err_force_close_connections_idle_not_available">FST_ERR_FORCE_CLOSE_CONNECTIONS_IDLE_NOT_AVAILABLE</a> | Cannot set forceCloseConnections to `idle` as your HTTP server does not support `closeIdleConnections` method. | Use a different value for `forceCloseConnections`. | [#3925](https://github.com/fastify/fastify/pull/3925) |
|
||||
| <a id="fst_err_duplicated_route">FST_ERR_DUPLICATED_ROUTE</a> | The HTTP method already has a registered controller for that URL. | Use a different URL or register the controller for another HTTP method. | [#2954](https://github.com/fastify/fastify/pull/2954) |
|
||||
| <a id="fst_err_bad_url">FST_ERR_BAD_URL</a> | The router received an invalid URL. | Use a valid URL. | [#2106](https://github.com/fastify/fastify/pull/2106) |
|
||||
| <a id="fst_err_async_constraint">FST_ERR_ASYNC_CONSTRAINT</a> | The router received an error when using asynchronous constraints. | - | [#4323](https://github.com/fastify/fastify/pull/4323) |
|
||||
| <a id="fst_err_default_route_invalid_type">FST_ERR_DEFAULT_ROUTE_INVALID_TYPE</a> | The `defaultRoute` type should be a function. | Use a function for the `defaultRoute`. | [#2733](https://github.com/fastify/fastify/pull/2733) |
|
||||
| <a id="fst_err_invalid_url">FST_ERR_INVALID_URL</a> | URL must be a string. | Use a string for the URL. | [#3653](https://github.com/fastify/fastify/pull/3653) |
|
||||
| <a id="fst_err_route_options_not_obj">FST_ERR_ROUTE_OPTIONS_NOT_OBJ</a> | Options for the route must be an object. | Use an object for the route options. | [#4554](https://github.com/fastify/fastify/pull/4554) |
|
||||
| <a id="fst_err_route_duplicated_handler">FST_ERR_ROUTE_DUPLICATED_HANDLER</a> | Duplicate handler for the route is not allowed. | Use a different handler. | [#4554](https://github.com/fastify/fastify/pull/4554) |
|
||||
@@ -359,7 +366,7 @@ Below is a table with all the error codes that Fastify uses.
|
||||
| <a id="fst_err_parent_plugin_booted">FST_ERR_PARENT_PLUGIN_BOOTED</a> | Impossible to load plugin because the parent (mapped directly from `avvio`) | - | [#3106](https://github.com/fastify/fastify/pull/3106) |
|
||||
| <a id="fst_err_plugin_timeout">FST_ERR_PLUGIN_TIMEOUT</a> | Plugin did not start in time. | Increase the timeout for the plugin. | [#3106](https://github.com/fastify/fastify/pull/3106) |
|
||||
| <a id="fst_err_plugin_not_present_in_instance">FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE</a> | The decorator is not present in the instance. | - | [#4554](https://github.com/fastify/fastify/pull/4554) |
|
||||
| <a id="fst_err_plugin_invalid_async_handler">FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER</a> | The plugin being registered mixes async and callback styles. | - | [#5141](https://github.com/fastify/fastify/pull/5141) |
|
||||
| <a id="fst_err_validation">FST_ERR_VALIDATION</a> | The Request failed the payload validation. | Check the request payload. | [#4824](https://github.com/fastify/fastify/pull/4824) |
|
||||
| <a id="fst_err_listen_options_invalid">FST_ERR_LISTEN_OPTIONS_INVALID</a> | Invalid listen options. | Check the listen options. | [#4886](https://github.com/fastify/fastify/pull/4886) |
|
||||
| <a id="fst_err_error_handler_not_fn">FST_ERR_ERROR_HANDLER_NOT_FN</a> | Error Handler must be a function | Provide a function to `setErrorHandler`. | [#5317](https://github.com/fastify/fastify/pull/5317) |
|
||||
|
||||
| <a id="fst_err_error_handler_not_fn">FST_ERR_ERROR_HANDLER_NOT_FN</a> | Error Handler must be a function | Provide a function to `setErrorHandler`. | [#5317](https://github.com/fastify/fastify/pull/5317) | <a id="fst_err_error_handler_already_set">FST_ERR_ERROR_HANDLER_ALREADY_SET</a> | Error Handler already set in this scope. Set `allowErrorHandlerOverride: true` to allow overriding. | By default, `setErrorHandler` can only be called once per encapsulation context. | [#6097](https://github.com/fastify/fastify/pull/6098) |
|
||||
|
||||
14
backend/node_modules/fastify/docs/Reference/HTTP2.md
generated
vendored
14
backend/node_modules/fastify/docs/Reference/HTTP2.md
generated
vendored
@@ -2,11 +2,11 @@
|
||||
|
||||
## HTTP2
|
||||
|
||||
_Fastify_ supports HTTP2 over either HTTPS (h2) or plaintext (h2c).
|
||||
_Fastify_ supports HTTP2 over HTTPS (h2) or plaintext (h2c).
|
||||
|
||||
Currently, none of the HTTP2-specific APIs are available through _Fastify_, but
|
||||
Node's `req` and `res` can be accessed through our `Request` and `Reply`
|
||||
interface. PRs are welcome.
|
||||
Node's `req` and `res` can be accessed through the `Request` and `Reply`
|
||||
interfaces. PRs are welcome.
|
||||
|
||||
### Secure (HTTPS)
|
||||
|
||||
@@ -61,7 +61,7 @@ fastify.get('/', function (request, reply) {
|
||||
fastify.listen({ port: 3000 })
|
||||
```
|
||||
|
||||
You can test your new server with:
|
||||
Test the new server with:
|
||||
|
||||
```
|
||||
$ npx h2url https://localhost:3000
|
||||
@@ -69,8 +69,8 @@ $ npx h2url https://localhost:3000
|
||||
|
||||
### Plain or insecure
|
||||
|
||||
If you are building microservices, you can connect to HTTP2 in plain text,
|
||||
however, this is not supported by browsers.
|
||||
For microservices, HTTP2 can connect in plain text, but this is not
|
||||
supported by browsers.
|
||||
|
||||
```js
|
||||
'use strict'
|
||||
@@ -86,7 +86,7 @@ fastify.get('/', function (request, reply) {
|
||||
fastify.listen({ port: 3000 })
|
||||
```
|
||||
|
||||
You can test your new server with:
|
||||
Test the new server with:
|
||||
|
||||
```
|
||||
$ npx h2url http://localhost:3000
|
||||
|
||||
131
backend/node_modules/fastify/docs/Reference/Hooks.md
generated
vendored
131
backend/node_modules/fastify/docs/Reference/Hooks.md
generated
vendored
@@ -34,9 +34,9 @@ are Request/Reply hooks and application hooks:
|
||||
- [Using Hooks to Inject Custom Properties](#using-hooks-to-inject-custom-properties)
|
||||
- [Diagnostics Channel Hooks](#diagnostics-channel-hooks)
|
||||
|
||||
**Notice:** the `done` callback is not available when using `async`/`await` or
|
||||
returning a `Promise`. If you do invoke a `done` callback in this situation
|
||||
unexpected behavior may occur, e.g. duplicate invocation of handlers.
|
||||
> ℹ️ Note: The `done` callback is not available when using `async`/`await` or
|
||||
> returning a `Promise`. If you do invoke a `done` callback in this situation
|
||||
> unexpected behavior may occur, e.g. duplicate invocation of handlers.
|
||||
|
||||
## Request/Reply Hooks
|
||||
|
||||
@@ -68,9 +68,9 @@ fastify.addHook('onRequest', async (request, reply) => {
|
||||
})
|
||||
```
|
||||
|
||||
**Notice:** in the [onRequest](#onrequest) hook, `request.body` will always be
|
||||
`undefined`, because the body parsing happens before the
|
||||
[preValidation](#prevalidation) hook.
|
||||
> ℹ️ Note: In the [onRequest](#onrequest) hook, `request.body` will always be
|
||||
> `undefined`, because the body parsing happens before the
|
||||
> [preValidation](#prevalidation) hook.
|
||||
|
||||
### preParsing
|
||||
|
||||
@@ -98,17 +98,17 @@ fastify.addHook('preParsing', async (request, reply, payload) => {
|
||||
})
|
||||
```
|
||||
|
||||
**Notice:** in the [preParsing](#preparsing) hook, `request.body` will always be
|
||||
`undefined`, because the body parsing happens before the
|
||||
[preValidation](#prevalidation) hook.
|
||||
> ℹ️ Note: In the [preParsing](#preparsing) hook, `request.body` will always be
|
||||
> `undefined`, because the body parsing happens before the
|
||||
> [preValidation](#prevalidation) hook.
|
||||
|
||||
**Notice:** you should also add a `receivedEncodedLength` property to the
|
||||
returned stream. This property is used to correctly match the request payload
|
||||
with the `Content-Length` header value. Ideally, this property should be updated
|
||||
on each received chunk.
|
||||
> ℹ️ Note: You should also add a `receivedEncodedLength` property to the
|
||||
> returned stream. This property is used to correctly match the request payload
|
||||
> with the `Content-Length` header value. Ideally, this property should be updated
|
||||
> on each received chunk.
|
||||
|
||||
**Notice:** The size of the returned stream is checked to not exceed the limit
|
||||
set in [`bodyLimit`](./Server.md#bodylimit) option.
|
||||
> ℹ️ Note: The size of the returned stream is checked to not exceed the limit
|
||||
> set in [`bodyLimit`](./Server.md#bodylimit) option.
|
||||
|
||||
### preValidation
|
||||
|
||||
@@ -166,8 +166,8 @@ fastify.addHook('preSerialization', async (request, reply, payload) => {
|
||||
})
|
||||
```
|
||||
|
||||
Note: the hook is NOT called if the payload is a `string`, a `Buffer`, a
|
||||
`stream`, or `null`.
|
||||
> ℹ️ Note: The hook is NOT called if the payload is a `string`, a `Buffer`, a
|
||||
> `stream`, or `null`.
|
||||
|
||||
### onError
|
||||
```js
|
||||
@@ -189,15 +189,11 @@ specific header in case of error.
|
||||
It is not intended for changing the error, and calling `reply.send` will throw
|
||||
an exception.
|
||||
|
||||
This hook will be executed only after
|
||||
the [Custom Error Handler set by `setErrorHandler`](./Server.md#seterrorhandler)
|
||||
has been executed, and only if the custom error handler sends an error back to the
|
||||
user
|
||||
*(Note that the default error handler always sends the error back to the
|
||||
user)*.
|
||||
This hook will be executed before
|
||||
the [Custom Error Handler set by `setErrorHandler`](./Server.md#seterrorhandler).
|
||||
|
||||
**Notice:** unlike the other hooks, passing an error to the `done` function is not
|
||||
supported.
|
||||
> ℹ️ Note: Unlike the other hooks, passing an error to the `done` function is not
|
||||
> supported.
|
||||
|
||||
### onSend
|
||||
If you are using the `onSend` hook, you can change the payload. For example:
|
||||
@@ -233,8 +229,8 @@ fastify.addHook('onSend', (request, reply, payload, done) => {
|
||||
> to `0`, whereas the `Content-Length` header will not be set if the payload is
|
||||
> `null`.
|
||||
|
||||
Note: If you change the payload, you may only change it to a `string`, a
|
||||
`Buffer`, a `stream`, a `ReadableStream`, a `Response`, or `null`.
|
||||
> ℹ️ Note: If you change the payload, you may only change it to a `string`, a
|
||||
> `Buffer`, a `stream`, a `ReadableStream`, a `Response`, or `null`.
|
||||
|
||||
|
||||
### onResponse
|
||||
@@ -256,8 +252,8 @@ The `onResponse` hook is executed when a response has been sent, so you will not
|
||||
be able to send more data to the client. It can however be useful for sending
|
||||
data to external services, for example, to gather statistics.
|
||||
|
||||
**Note:** setting `disableRequestLogging` to `true` will disable any error log
|
||||
inside the `onResponse` hook. In this case use `try - catch` to log errors.
|
||||
> ℹ️ Note: Setting `disableRequestLogging` to `true` will disable any error log
|
||||
> inside the `onResponse` hook. In this case use `try - catch` to log errors.
|
||||
|
||||
### onTimeout
|
||||
|
||||
@@ -298,7 +294,8 @@ The `onRequestAbort` hook is executed when a client closes the connection before
|
||||
the entire request has been processed. Therefore, you will not be able to send
|
||||
data to the client.
|
||||
|
||||
**Notice:** client abort detection is not completely reliable. See: [`Detecting-When-Clients-Abort.md`](../Guides/Detecting-When-Clients-Abort.md)
|
||||
> ℹ️ Note: Client abort detection is not completely reliable.
|
||||
> See: [`Detecting-When-Clients-Abort.md`](../Guides/Detecting-When-Clients-Abort.md)
|
||||
|
||||
### Manage Errors from a hook
|
||||
If you get an error during the execution of your hook, just pass it to `done()`
|
||||
@@ -428,8 +425,8 @@ fastify.addHook('onReady', async function () {
|
||||
|
||||
### onListen
|
||||
|
||||
Triggered when the server starts listening for requests. The hooks run one
|
||||
after another. If a hook function causes an error, it is logged and
|
||||
Triggered when the server starts listening for requests. The hooks run one
|
||||
after another. If a hook function causes an error, it is logged and
|
||||
ignored, allowing the queue of hooks to continue. Hook functions accept one
|
||||
argument: a callback, `done`, to be invoked after the hook function is
|
||||
complete. Hook functions are invoked with `this` bound to the associated
|
||||
@@ -451,8 +448,8 @@ fastify.addHook('onListen', async function () {
|
||||
})
|
||||
```
|
||||
|
||||
> **Note**
|
||||
> This hook will not run when the server is started using `fastify.inject()` or `fastify.ready()`
|
||||
> ℹ️ Note: This hook will not run when the server is started using
|
||||
> fastify.inject()` or `fastify.ready()`.
|
||||
|
||||
### onClose
|
||||
<a id="on-close"></a>
|
||||
@@ -462,7 +459,7 @@ HTTP requests have been completed.
|
||||
It is useful when [plugins](./Plugins.md) need a "shutdown" event, for example,
|
||||
to close an open connection to a database.
|
||||
|
||||
The hook function takes the Fastify instance as a first argument,
|
||||
The hook function takes the Fastify instance as a first argument,
|
||||
and a `done` callback for synchronous hook functions.
|
||||
```js
|
||||
// callback style
|
||||
@@ -575,8 +572,8 @@ This hook can be useful if you are developing a plugin that needs to know when a
|
||||
plugin context is formed, and you want to operate in that specific context, thus
|
||||
this hook is encapsulated.
|
||||
|
||||
**Note:** This hook will not be called if a plugin is wrapped inside
|
||||
[`fastify-plugin`](https://github.com/fastify/fastify-plugin).
|
||||
> ℹ️ Note: This hook will not be called if a plugin is wrapped inside
|
||||
> [`fastify-plugin`](https://github.com/fastify/fastify-plugin).
|
||||
```js
|
||||
fastify.decorate('data', [])
|
||||
|
||||
@@ -773,7 +770,7 @@ fastify.route({
|
||||
})
|
||||
```
|
||||
|
||||
**Note**: both options also accept an array of functions.
|
||||
> ℹ️ Note: Both options also accept an array of functions.
|
||||
|
||||
## Using Hooks to Inject Custom Properties
|
||||
<a id="using-hooks-to-inject-custom-properties"></a>
|
||||
@@ -828,19 +825,11 @@ consider creating a custom [Plugin](./Plugins.md) instead.
|
||||
|
||||
## Diagnostics Channel Hooks
|
||||
|
||||
> **Note:** The `diagnostics_channel` is currently experimental on Node.js, so
|
||||
> its API is subject to change even in semver-patch releases of Node.js. For
|
||||
> versions of Node.js supported by Fastify where `diagnostics_channel` is
|
||||
> unavailable, the hook will use the
|
||||
> [polyfill](https://www.npmjs.com/package/diagnostics_channel) if it is
|
||||
> available. Otherwise, this feature will not be present.
|
||||
|
||||
Currently, one
|
||||
[`diagnostics_channel`](https://nodejs.org/api/diagnostics_channel.html) publish
|
||||
event, `'fastify.initialization'`, happens at initialization time. The Fastify
|
||||
instance is passed into the hook as a property of the object passed in. At this
|
||||
point, the instance can be interacted with to add hooks, plugins, routes, or any
|
||||
other sort of modification.
|
||||
One [`diagnostics_channel`](https://nodejs.org/api/diagnostics_channel.html)
|
||||
publish event, `'fastify.initialization'`, happens at initialization time. The
|
||||
Fastify instance is passed into the hook as a property of the object passed in.
|
||||
At this point, the instance can be interacted with to add hooks, plugins,
|
||||
routes, or any other sort of modification.
|
||||
|
||||
For example, a tracing package might do something like the following (which is,
|
||||
of course, a simplification). This would be in a file loaded in the
|
||||
@@ -855,7 +844,7 @@ const spans = new WeakMap()
|
||||
|
||||
channel.subscribe(function ({ fastify }) {
|
||||
fastify.addHook('onRequest', (request, reply, done) => {
|
||||
const span = tracer.startSpan('fastify.request')
|
||||
const span = tracer.startSpan('fastify.request.handler')
|
||||
spans.set(request, span)
|
||||
done()
|
||||
})
|
||||
@@ -867,3 +856,41 @@ channel.subscribe(function ({ fastify }) {
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
> ℹ️ Note: The TracingChannel class API is currently experimental and may undergo
|
||||
> breaking changes even in semver-patch releases of Node.js.
|
||||
|
||||
Five other events are published on a per-request basis following the
|
||||
[Tracing Channel](https://nodejs.org/api/diagnostics_channel.html#class-tracingchannel)
|
||||
nomenclature. The list of the channel names and the event they receive is:
|
||||
|
||||
- `tracing:fastify.request.handler:start`: Always fires
|
||||
- `{ request: Request, reply: Reply, route: { url, method } }`
|
||||
- `tracing:fastify.request.handler:end`: Always fires
|
||||
- `{ request: Request, reply: Reply, route: { url, method }, async: Bool }`
|
||||
- `tracing:fastify.request.handler:asyncStart`: Fires for promise/async handlers
|
||||
- `{ request: Request, reply: Reply, route: { url, method } }`
|
||||
- `tracing:fastify.request.handler:asyncEnd`: Fires for promise/async handlers
|
||||
- `{ request: Request, reply: Reply, route: { url, method } }`
|
||||
- `tracing:fastify.request.handler:error`: Fires when an error occurs
|
||||
- `{ request: Request, reply: Reply, route: { url, method }, error: Error }`
|
||||
|
||||
The object instance remains the same for all events associated with a given
|
||||
request. All payloads include a `request` and `reply` property which are an
|
||||
instance of Fastify's `Request` and `Reply` instances. They also include a
|
||||
`route` property which is an object with the matched `url` pattern (e.g.
|
||||
`/collection/:id`) and the `method` HTTP method (e.g. `GET`). The `:start` and
|
||||
`:end` events always fire for requests. If a request handler is an `async`
|
||||
function or one that returns a `Promise` then the `:asyncStart` and `:asyncEnd`
|
||||
events also fire. Finally, the `:error` event contains an `error` property
|
||||
associated with the request's failure.
|
||||
|
||||
These events can be received like so:
|
||||
|
||||
```js
|
||||
const dc = require('node:diagnostics_channel')
|
||||
const channel = dc.channel('tracing:fastify.request.handler:start')
|
||||
channel.subscribe((msg) => {
|
||||
console.log(msg.request, msg.reply)
|
||||
})
|
||||
```
|
||||
|
||||
44
backend/node_modules/fastify/docs/Reference/LTS.md
generated
vendored
44
backend/node_modules/fastify/docs/Reference/LTS.md
generated
vendored
@@ -1,8 +1,7 @@
|
||||
<h1 align="center">Fastify</h1>
|
||||
|
||||
## Long Term Support
|
||||
|
||||
`<a id="lts"></a>`
|
||||
<a id="lts"></a>
|
||||
|
||||
Fastify's Long Term Support (LTS) is provided according to the schedule laid out
|
||||
in this document:
|
||||
@@ -25,13 +24,11 @@ in this document:
|
||||
and verified against alternative runtimes that are compatible with Node.js.
|
||||
The maintenance teams of these alternative runtimes are responsible for ensuring
|
||||
and guaranteeing these tests work properly.
|
||||
1. [N|Solid](https://docs.nodesource.com/nsolid), maintained by NodeSource,
|
||||
commits to testing and verifying each Fastify major release against the N|Solid
|
||||
LTS versions that are current at the time of the Fastify release.
|
||||
NodeSource guarantees that Fastify will be compatible and function correctly
|
||||
with N|Solid, aligning with the support and compatibility scope of the N|Solid
|
||||
LTS versions available at the time of the Fastify release.
|
||||
This ensures users of N|Solid can confidently use Fastify.
|
||||
1. [N|Solid](https://docs.nodesource.com/docs/product_suite) tests and
|
||||
verifies each Fastify major release against current N|Solid LTS versions.
|
||||
NodeSource ensures Fastify compatibility with N|Solid, aligning with the
|
||||
support scope of N|Solid LTS versions at the time of the Fastify release.
|
||||
This guarantees N|Solid users can confidently use Fastify.
|
||||
|
||||
A "month" is defined as 30 consecutive days.
|
||||
|
||||
@@ -41,27 +38,32 @@ A "month" is defined as 30 consecutive days.
|
||||
> occasions where we need to release breaking changes as a _minor_ version
|
||||
> release. Such changes will _always_ be noted in the [release
|
||||
> notes](https://github.com/fastify/fastify/releases).
|
||||
>
|
||||
>
|
||||
> To avoid automatically receiving breaking security updates it is possible to
|
||||
> use the tilde (`~`) range qualifier. For example, to get patches for the 3.15
|
||||
> release, and avoid automatically updating to the 3.16 release, specify the
|
||||
> dependency as `"fastify": "~3.15.x"`. This will leave your application
|
||||
> vulnerable, so please use with caution.
|
||||
> vulnerable, so please use it with caution.
|
||||
|
||||
### Security Support Beyond LTS
|
||||
|
||||
Fastify's partner, HeroDevs, provides commercial security support through the
|
||||
OpenJS Ecosystem Sustainability Program for versions of Fastify that are EOL.
|
||||
For more information, see their [Never Ending Support][hd-link] service.
|
||||
|
||||
### Schedule
|
||||
|
||||
`<a id="lts-schedule"></a>`
|
||||
<a id="lts-schedule"></a>
|
||||
|
||||
| Version | Release Date | End Of LTS Date | Node.js | Nsolid(Node) |
|
||||
| :------ | :----------- | :-------------- | :----------------- | :------------- |
|
||||
| 1.0.0 | 2018-03-06 | 2019-09-01 | 6, 8, 9, 10, 11 | |
|
||||
| 2.0.0 | 2019-02-25 | 2021-01-31 | 6, 8, 10, 12, 14 | |
|
||||
| 3.0.0 | 2020-07-07 | 2023-06-30 | 10, 12, 14, 16, 18 | v5(18) |
|
||||
| 4.0.0 | 2022-06-08 | TBD | 14, 16, 18, 20 | v5(18), v5(20) |
|
||||
| 4.0.0 | 2022-06-08 | 2025-06-30 | 14, 16, 18, 20, 22 | v5(18), v5(20) |
|
||||
| 5.0.0 | 2024-09-17 | TBD | 20, 22 | v5(20) |
|
||||
|
||||
### CI tested operating systems
|
||||
|
||||
`<a id="supported-os"></a>`
|
||||
<a id="supported-os"></a>
|
||||
|
||||
Fastify uses GitHub Actions for CI testing, please refer to [GitHub's
|
||||
documentation regarding workflow
|
||||
@@ -71,12 +73,14 @@ YAML workflow labels below:
|
||||
|
||||
| OS | YAML Workflow Label | Package Manager | Node.js | Nsolid(Node) |
|
||||
| ------- | ------------------- | --------------- | ----------- | ------------- |
|
||||
| Linux | `ubuntu-latest` | npm | 14,16,18,20 | v5(18),v5(20) |
|
||||
| Linux | `ubuntu-latest` | yarn,pnpm | 14,16,18,20 | v5(18),v5(20) |
|
||||
| Windows | `windows-latest` | npm | 14,16,18,20 | v5(18),v5(20) |
|
||||
| MacOS | `macos-latest` | npm | 14,16,18,20 | v5(18),v5(20) |
|
||||
| Linux | `ubuntu-latest` | npm | 20 | v5(20) |
|
||||
| Linux | `ubuntu-latest` | yarn,pnpm | 20 | v5(20) |
|
||||
| Windows | `windows-latest` | npm | 20 | v5(20) |
|
||||
| MacOS | `macos-latest` | npm | 20 | v5(20) |
|
||||
|
||||
Using [yarn](https://yarnpkg.com/) might require passing the `--ignore-engines`
|
||||
flag.
|
||||
|
||||
[semver]: https://semver.org/
|
||||
|
||||
[hd-link]: https://www.herodevs.com/support/fastify-nes?utm_source=fastify&utm_medium=link&utm_campaign=eol_support_fastify
|
||||
|
||||
47
backend/node_modules/fastify/docs/Reference/Lifecycle.md
generated
vendored
47
backend/node_modules/fastify/docs/Reference/Lifecycle.md
generated
vendored
@@ -3,12 +3,11 @@
|
||||
## Lifecycle
|
||||
<a id="lifecycle"></a>
|
||||
|
||||
Following the schema of the internal lifecycle of Fastify.
|
||||
This schema shows the internal lifecycle of Fastify.
|
||||
|
||||
On the right branch of every section there is the next phase of the lifecycle,
|
||||
on the left branch there is the corresponding error code that will be generated
|
||||
if the parent throws an error *(note that all the errors are automatically
|
||||
handled by Fastify)*.
|
||||
The right branch of each section shows the next phase of the lifecycle. The left
|
||||
branch shows the corresponding error code generated if the parent throws an
|
||||
error. All errors are automatically handled by Fastify.
|
||||
|
||||
```
|
||||
Incoming Request
|
||||
@@ -42,26 +41,23 @@ Incoming Request
|
||||
└─▶ onResponse Hook
|
||||
```
|
||||
|
||||
At any point before or during the `User Handler`, `reply.hijack()` can be called
|
||||
to prevent Fastify from:
|
||||
- Running all the following hooks and user handler
|
||||
- Sending the response automatically
|
||||
Before or during the `User Handler`, `reply.hijack()` can be called to:
|
||||
- Prevent Fastify from running subsequent hooks and the user handler
|
||||
- Prevent Fastify from sending the response automatically
|
||||
|
||||
NB (*): If `reply.raw` is used to send a response back to the user, `onResponse`
|
||||
hooks will still be executed
|
||||
If `reply.raw` is used to send a response, `onResponse` hooks will still
|
||||
be executed.
|
||||
|
||||
## Reply Lifecycle
|
||||
<a id="reply-lifecycle"></a>
|
||||
|
||||
Whenever the user handles the request, the result may be:
|
||||
When the user handles the request, the result may be:
|
||||
|
||||
- in async handler: it returns a payload
|
||||
- in async handler: it throws an `Error`
|
||||
- in sync handler: it sends a payload
|
||||
- in sync handler: it sends an `Error` instance
|
||||
- In an async handler: it returns a payload or throws an `Error`
|
||||
- In a sync handler: it sends a payload or an `Error` instance
|
||||
|
||||
If the reply was hijacked, we skip all the below steps. Otherwise, when it is
|
||||
being submitted, the data flow performed is the following:
|
||||
If the reply was hijacked, all subsequent steps are skipped. Otherwise, when
|
||||
submitted, the data flow is as follows:
|
||||
|
||||
```
|
||||
★ schema validation Error
|
||||
@@ -74,16 +70,15 @@ being submitted, the data flow performed is the following:
|
||||
★ send or return │ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
reply sent ◀── JSON ─┴─ Error instance ──▶ setErrorHandler ◀─────┘
|
||||
reply sent ◀── JSON ─┴─ Error instance ──▶ onError Hook ◀───────┘
|
||||
│
|
||||
reply sent ◀── JSON ─┴─ Error instance ──▶ onError Hook
|
||||
reply sent ◀── JSON ─┴─ Error instance ──▶ setErrorHandler
|
||||
│
|
||||
└─▶ reply sent
|
||||
```
|
||||
|
||||
Note: `reply sent` means that the JSON payload will be serialized by:
|
||||
|
||||
- the [reply serialized](./Server.md#setreplyserializer) if set
|
||||
- or by the [serializer compiler](./Server.md#setserializercompiler) when a JSON
|
||||
schema has been set for the returning HTTP status code
|
||||
- or by the default `JSON.stringify` function
|
||||
`reply sent` means the JSON payload will be serialized by one of the following:
|
||||
- The [reply serializer](./Server.md#setreplyserializer) if set
|
||||
- The [serializer compiler](./Server.md#setserializercompiler) if a JSON schema
|
||||
is set for the HTTP status code
|
||||
- The default `JSON.stringify` function
|
||||
120
backend/node_modules/fastify/docs/Reference/Logging.md
generated
vendored
120
backend/node_modules/fastify/docs/Reference/Logging.md
generated
vendored
@@ -2,17 +2,18 @@
|
||||
|
||||
## Logging
|
||||
|
||||
### Enable logging
|
||||
Logging is disabled by default, and you can enable it by passing `{ logger: true
|
||||
}` or `{ logger: { level: 'info' } }` when you create a Fastify instance. Note
|
||||
that if the logger is disabled, it is impossible to enable it at runtime. We use
|
||||
[abstract-logging](https://www.npmjs.com/package/abstract-logging) for this
|
||||
purpose.
|
||||
### Enable Logging
|
||||
Logging is disabled by default. Enable it by passing `{ logger: true }` or
|
||||
`{ logger: { level: 'info' } }` when creating a Fastify instance. Note that if
|
||||
the logger is disabled, it cannot be enabled at runtime.
|
||||
[abstract-logging](https://www.npmjs.com/package/abstract-logging) is used for
|
||||
this purpose.
|
||||
|
||||
As Fastify is focused on performance, it uses
|
||||
[pino](https://github.com/pinojs/pino) as its logger, with the default log
|
||||
level, when enabled, set to `'info'`.
|
||||
level set to `'info'` when enabled.
|
||||
|
||||
#### Basic logging setup
|
||||
Enabling the production JSON logger:
|
||||
|
||||
```js
|
||||
@@ -21,8 +22,9 @@ const fastify = require('fastify')({
|
||||
})
|
||||
```
|
||||
|
||||
Enabling the logger with appropriate configuration for both local development
|
||||
and production and test environment requires a bit more configuration:
|
||||
#### Environment-Specific Configuration
|
||||
Enabling the logger with appropriate configuration for local development,
|
||||
production, and test environments requires more configuration:
|
||||
|
||||
```js
|
||||
const envToLogger = {
|
||||
@@ -42,11 +44,11 @@ const fastify = require('fastify')({
|
||||
logger: envToLogger[environment] ?? true // defaults to true if no entry matches in the map
|
||||
})
|
||||
```
|
||||
⚠️ `pino-pretty` needs to be installed as a dev dependency, it is not included
|
||||
⚠️ `pino-pretty` needs to be installed as a dev dependency. It is not included
|
||||
by default for performance reasons.
|
||||
|
||||
### Usage
|
||||
You can use the logger like this in your route handlers:
|
||||
The logger can be used in route handlers as follows:
|
||||
|
||||
```js
|
||||
fastify.get('/', options, function (request, reply) {
|
||||
@@ -55,16 +57,16 @@ fastify.get('/', options, function (request, reply) {
|
||||
})
|
||||
```
|
||||
|
||||
You can trigger new logs outside route handlers by using the Pino instance from
|
||||
the Fastify instance:
|
||||
Trigger new logs outside route handlers using the Pino instance from the Fastify
|
||||
instance:
|
||||
```js
|
||||
fastify.log.info('Something important happened!');
|
||||
```
|
||||
|
||||
If you want to pass some options to the logger, just pass them to Fastify.
|
||||
You can find all available options in the
|
||||
[Pino documentation](https://github.com/pinojs/pino/blob/master/docs/api.md#options).
|
||||
If you want to specify a file destination, use:
|
||||
#### Passing Logger Options
|
||||
To pass options to the logger, provide them to Fastify. See the
|
||||
[Pino documentation](https://github.com/pinojs/pino/blob/master/docs/api.md#options)
|
||||
for available options. To specify a file destination, use:
|
||||
|
||||
```js
|
||||
const fastify = require('fastify')({
|
||||
@@ -80,8 +82,8 @@ fastify.get('/', options, function (request, reply) {
|
||||
})
|
||||
```
|
||||
|
||||
If you want to pass a custom stream to the Pino instance, just add a stream
|
||||
field to the logger object.
|
||||
To pass a custom stream to the Pino instance, add a `stream` field to the logger
|
||||
object:
|
||||
|
||||
```js
|
||||
const split = require('split2')
|
||||
@@ -95,19 +97,25 @@ const fastify = require('fastify')({
|
||||
})
|
||||
```
|
||||
|
||||
<a id="logging-request-id"></a>
|
||||
### Advanced Logger Configuration
|
||||
|
||||
<a id="logging-request-id"></a>
|
||||
#### Request ID Tracking
|
||||
By default, Fastify adds an ID to every request for easier tracking. If the
|
||||
"request-id" header is present its value is used, otherwise a new incremental ID
|
||||
is generated. See Fastify Factory
|
||||
`requestIdHeader` option is set and the corresponding header is present, its
|
||||
value is used; otherwise, a new incremental ID is generated. See Fastify Factory
|
||||
[`requestIdHeader`](./Server.md#factory-request-id-header) and Fastify Factory
|
||||
[`genReqId`](./Server.md#genreqid) for customization options.
|
||||
|
||||
The default logger is configured with a set of standard serializers that
|
||||
serialize objects with `req`, `res`, and `err` properties. The object received
|
||||
by `req` is the Fastify [`Request`](./Request.md) object, while the object
|
||||
received by `res` is the Fastify [`Reply`](./Reply.md) object. This behavior
|
||||
can be customized by specifying custom serializers.
|
||||
> ⚠ Warning: enabling `requestIdHeader` allows any callers to set `reqId` to a
|
||||
> value of their choosing.
|
||||
> No validation is performed on `requestIdHeader`.
|
||||
|
||||
#### Serializers
|
||||
The default logger uses standard serializers for objects with `req`, `res`, and
|
||||
`err` properties. The `req` object is the Fastify [`Request`](./Request.md)
|
||||
object, and the `res` object is the Fastify [`Reply`](./Reply.md) object. This
|
||||
behavior can be customized with custom serializers.
|
||||
|
||||
```js
|
||||
const fastify = require('fastify')({
|
||||
@@ -121,7 +129,7 @@ const fastify = require('fastify')({
|
||||
})
|
||||
```
|
||||
For example, the response payload and headers could be logged using the approach
|
||||
below (even if it is *not recommended*):
|
||||
below (not recommended):
|
||||
|
||||
```js
|
||||
const fastify = require('fastify')({
|
||||
@@ -140,12 +148,11 @@ const fastify = require('fastify')({
|
||||
return {
|
||||
method: request.method,
|
||||
url: request.url,
|
||||
path: request.routerPath,
|
||||
path: request.routeOptions.url,
|
||||
parameters: request.params,
|
||||
// Including the headers in the log could be in violation
|
||||
// of privacy laws, e.g. GDPR. You should use the "redact" option to
|
||||
// remove sensitive fields. It could also leak authentication data in
|
||||
// the logs.
|
||||
// Including headers in the log could violate privacy laws,
|
||||
// e.g., GDPR. Use the "redact" option to remove sensitive
|
||||
// fields. It could also leak authentication data in the logs.
|
||||
headers: request.headers
|
||||
};
|
||||
}
|
||||
@@ -154,11 +161,11 @@ const fastify = require('fastify')({
|
||||
});
|
||||
```
|
||||
|
||||
**Note**: In certain cases, the [`Reply`](./Reply.md) object passed to the `res`
|
||||
serializer cannot be fully constructed. When writing a custom `res` serializer,
|
||||
it is necessary to check for the existence of any properties on `reply` aside
|
||||
from `statusCode`, which is always present. For example, the existence of
|
||||
`getHeaders` must be verified before it can be called:
|
||||
> ℹ️ Note: In some cases, the [`Reply`](./Reply.md) object passed to the `res`
|
||||
> serializer cannot be fully constructed. When writing a custom `res`
|
||||
> serializer, check for the existence of any properties on `reply` aside from
|
||||
> `statusCode`, which is always present. For example, verify the existence of
|
||||
> `getHeaders` before calling it:
|
||||
|
||||
```js
|
||||
const fastify = require('fastify')({
|
||||
@@ -170,7 +177,7 @@ const fastify = require('fastify')({
|
||||
res (reply) {
|
||||
// The default
|
||||
return {
|
||||
statusCode: reply.statusCode
|
||||
statusCode: reply.statusCode,
|
||||
headers: typeof reply.getHeaders === 'function'
|
||||
? reply.getHeaders()
|
||||
: {}
|
||||
@@ -181,11 +188,11 @@ const fastify = require('fastify')({
|
||||
});
|
||||
```
|
||||
|
||||
**Note**: The body cannot be serialized inside a `req` method because the
|
||||
request is serialized when we create the child logger. At that time, the body is
|
||||
not yet parsed.
|
||||
> ℹ️ Note: The body cannot be serialized inside a `req` method because the
|
||||
request is serialized when the child logger is created. At that time, the body
|
||||
is not yet parsed.
|
||||
|
||||
See an approach to log `req.body`
|
||||
See the following approach to log `req.body`:
|
||||
|
||||
```js
|
||||
app.addHook('preHandler', function (req, reply, done) {
|
||||
@@ -196,23 +203,24 @@ app.addHook('preHandler', function (req, reply, done) {
|
||||
})
|
||||
```
|
||||
|
||||
**Note**: Care should be taken to ensure serializers never throw, as an error
|
||||
thrown from a serializer has the potential to cause the Node process to exit.
|
||||
See the [Pino documentation](https://getpino.io/#/docs/api?id=opt-serializers)
|
||||
on serializers for more information.
|
||||
> ℹ️ Note: Ensure serializers never throw errors, as this can cause the Node
|
||||
> process to exit. See the
|
||||
> [Pino documentation](https://getpino.io/#/docs/api?id=opt-serializers) for more
|
||||
> information.
|
||||
|
||||
*Any logger other than Pino will ignore this option.*
|
||||
|
||||
You can also supply your own logger instance. Instead of passing configuration
|
||||
options, pass the instance. The logger you supply must conform to the Pino
|
||||
interface; that is, it must have the following methods: `info`, `error`,
|
||||
`debug`, `fatal`, `warn`, `trace`, `silent`, `child` and a string property `level`.
|
||||
### Using Custom Loggers
|
||||
A custom logger instance can be supplied by passing it as `loggerInstance`. The
|
||||
logger must conform to the Pino interface, with methods: `info`, `error`,
|
||||
`debug`, `fatal`, `warn`, `trace`, `silent`, `child`, and a string property
|
||||
`level`.
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
const log = require('pino')({ level: 'info' })
|
||||
const fastify = require('fastify')({ logger: log })
|
||||
const fastify = require('fastify')({ loggerInstance: log })
|
||||
|
||||
log.info('does not have request information')
|
||||
|
||||
@@ -225,11 +233,11 @@ fastify.get('/', function (request, reply) {
|
||||
*The logger instance for the current request is available in every part of the
|
||||
[lifecycle](./Lifecycle.md).*
|
||||
|
||||
## Log Redaction
|
||||
### Log Redaction
|
||||
|
||||
[Pino](https://getpino.io) supports low-overhead log redaction for obscuring
|
||||
values of specific properties in recorded logs. As an example, we might want to
|
||||
log all the HTTP headers minus the `Authorization` header for security concerns:
|
||||
values of specific properties in recorded logs. For example, log all HTTP
|
||||
headers except the `Authorization` header for security:
|
||||
|
||||
```js
|
||||
const fastify = Fastify({
|
||||
@@ -243,7 +251,7 @@ const fastify = Fastify({
|
||||
method: request.method,
|
||||
url: request.url,
|
||||
headers: request.headers,
|
||||
hostname: request.hostname,
|
||||
host: request.host,
|
||||
remoteAddress: request.ip,
|
||||
remotePort: request.socket.remotePort
|
||||
}
|
||||
|
||||
38
backend/node_modules/fastify/docs/Reference/Middleware.md
generated
vendored
38
backend/node_modules/fastify/docs/Reference/Middleware.md
generated
vendored
@@ -22,36 +22,36 @@ fastify.use(require('ienoopen')())
|
||||
fastify.use(require('x-xss-protection')())
|
||||
```
|
||||
|
||||
You can also use [`@fastify/middie`](https://github.com/fastify/middie), which provides
|
||||
support for simple Express-style middleware but with improved performance:
|
||||
[`@fastify/middie`](https://github.com/fastify/middie) can also be used,
|
||||
which provides support for simple Express-style middleware with improved
|
||||
performance:
|
||||
|
||||
```js
|
||||
await fastify.register(require('@fastify/middie'))
|
||||
fastify.use(require('cors')())
|
||||
```
|
||||
|
||||
Remember that middleware can be encapsulated; this means that you can decide
|
||||
where your middleware should run by using `register` as explained in the
|
||||
[plugins guide](../Guides/Plugins-Guide.md).
|
||||
Middleware can be encapsulated, allowing control over where it runs using
|
||||
`register` as explained in the [plugins guide](../Guides/Plugins-Guide.md).
|
||||
|
||||
Fastify middleware does not expose the `send` method or other methods specific to
|
||||
the Fastify [Reply](./Reply.md#reply) instance. This is because Fastify wraps
|
||||
Fastify middleware does not expose the `send` method or other methods specific
|
||||
to the Fastify [Reply](./Reply.md#reply) instance. This is because Fastify wraps
|
||||
the incoming `req` and `res` Node instances using the
|
||||
[Request](./Request.md#request) and [Reply](./Reply.md#reply) objects
|
||||
internally, but this is done after the middleware phase. If you need to create
|
||||
middleware, you have to use the Node `req` and `res` instances. Otherwise, you
|
||||
can use the `preHandler` hook that already has the
|
||||
[Request](./Request.md#request) and [Reply](./Reply.md#reply) Fastify instances.
|
||||
For more information, see [Hooks](./Hooks.md#hooks).
|
||||
internally, but this is done after the middleware phase. To create middleware,
|
||||
use the Node `req` and `res` instances. Alternatively, use the `preHandler` hook
|
||||
that already has the Fastify [Request](./Request.md#request) and
|
||||
[Reply](./Reply.md#reply) instances. For more information, see
|
||||
[Hooks](./Hooks.md#hooks).
|
||||
|
||||
#### Restrict middleware execution to certain paths
|
||||
<a id="restrict-usage"></a>
|
||||
|
||||
If you need to only run middleware under certain paths, just pass the path as
|
||||
the first parameter to `use` and you are done!
|
||||
To run middleware under certain paths, pass the path as the first parameter to
|
||||
`use`.
|
||||
|
||||
*Note that this does not support routes with parameters, (e.g.
|
||||
`/user/:id/comments`) and wildcards are not supported in multiple paths.*
|
||||
> ℹ️ Note: This does not support routes with parameters
|
||||
> (e.g. `/user/:id/comments`) and wildcards are not supported in multiple paths.
|
||||
|
||||
```js
|
||||
const path = require('node:path')
|
||||
@@ -69,10 +69,10 @@ fastify.use(['/css', '/js'], serveStatic(path.join(__dirname, '/assets')))
|
||||
|
||||
### Alternatives
|
||||
|
||||
Fastify offers some alternatives to the most commonly used middleware, such as
|
||||
[`@fastify/helmet`](https://github.com/fastify/fastify-helmet) in case of
|
||||
Fastify offers alternatives to commonly used middleware, such as
|
||||
[`@fastify/helmet`](https://github.com/fastify/fastify-helmet) for
|
||||
[`helmet`](https://github.com/helmetjs/helmet),
|
||||
[`@fastify/cors`](https://github.com/fastify/fastify-cors) for
|
||||
[`cors`](https://github.com/expressjs/cors), and
|
||||
[`@fastify/static`](https://github.com/fastify/fastify-static) for
|
||||
[`serve-static`](https://github.com/expressjs/serve-static).
|
||||
[`serve-static`](https://github.com/expressjs/serve-static).
|
||||
133
backend/node_modules/fastify/docs/Reference/Plugins.md
generated
vendored
133
backend/node_modules/fastify/docs/Reference/Plugins.md
generated
vendored
@@ -1,21 +1,18 @@
|
||||
<h1 align="center">Fastify</h1>
|
||||
|
||||
## Plugins
|
||||
Fastify allows the user to extend its functionalities with plugins. A plugin can
|
||||
be a set of routes, a server [decorator](./Decorators.md), or whatever. The API
|
||||
that you will need to use one or more plugins, is `register`.
|
||||
Fastify can be extended with plugins, which can be a set of routes, a server
|
||||
[decorator](./Decorators.md), or other functionality. Use the `register` API to
|
||||
add one or more plugins.
|
||||
|
||||
By default, `register` creates a *new scope*, this means that if you make some
|
||||
changes to the Fastify instance (via `decorate`), this change will not be
|
||||
reflected by the current context ancestors, but only by its descendants. This
|
||||
feature allows us to achieve plugin *encapsulation* and *inheritance*, in this
|
||||
way we create a *directed acyclic graph* (DAG) and we will not have issues
|
||||
caused by cross dependencies.
|
||||
By default, `register` creates a *new scope*, meaning changes to the Fastify
|
||||
instance (via `decorate`) will not affect the current context ancestors, only
|
||||
its descendants. This feature enables plugin *encapsulation* and *inheritance*,
|
||||
creating a *directed acyclic graph* (DAG) and avoiding cross-dependency issues.
|
||||
|
||||
You may have already seen in the [Getting
|
||||
Started](../Guides/Getting-Started.md#your-first-plugin) guide how easy it is
|
||||
to use this API:
|
||||
```
|
||||
The [Getting Started](../Guides/Getting-Started.md#your-first-plugin) guide
|
||||
includes an example of using this API:
|
||||
```js
|
||||
fastify.register(plugin, [options])
|
||||
```
|
||||
|
||||
@@ -33,10 +30,9 @@ Fastify specific options is:
|
||||
+ [`logSerializers`](./Routes.md#custom-log-serializer)
|
||||
+ [`prefix`](#route-prefixing-option)
|
||||
|
||||
**Note: Those options will be ignored when used with fastify-plugin**
|
||||
These options will be ignored when used with fastify-plugin.
|
||||
|
||||
It is possible that Fastify will directly support other options in the future.
|
||||
Thus, to avoid collisions, a plugin should consider namespacing its options. For
|
||||
To avoid collisions, a plugin should consider namespacing its options. For
|
||||
example, a plugin `foo` might be registered like so:
|
||||
|
||||
```js
|
||||
@@ -49,8 +45,7 @@ fastify.register(require('fastify-foo'), {
|
||||
})
|
||||
```
|
||||
|
||||
If collisions are not a concern, the plugin may simply accept the options object
|
||||
as-is:
|
||||
If collisions are not a concern, the plugin may accept the options object as-is:
|
||||
|
||||
```js
|
||||
fastify.register(require('fastify-foo'), {
|
||||
@@ -60,9 +55,8 @@ fastify.register(require('fastify-foo'), {
|
||||
})
|
||||
```
|
||||
|
||||
The `options` parameter can also be a `Function` that will be evaluated at the
|
||||
time the plugin is registered while giving access to the Fastify instance via
|
||||
the first positional argument:
|
||||
The `options` parameter can also be a `Function` evaluated at plugin registration,
|
||||
providing access to the Fastify instance via the first argument:
|
||||
|
||||
```js
|
||||
const fp = require('fastify-plugin')
|
||||
@@ -77,40 +71,38 @@ fastify.register(fp((fastify, opts, done) => {
|
||||
fastify.register(require('fastify-foo'), parent => parent.foo_bar)
|
||||
```
|
||||
|
||||
The Fastify instance passed on to the function is the latest state of the
|
||||
**external Fastify instance** the plugin was declared on, allowing access to
|
||||
variables injected via [`decorate`](./Decorators.md) by preceding plugins
|
||||
according to the **order of registration**. This is useful in case a plugin
|
||||
depends on changes made to the Fastify instance by a preceding plugin i.e.
|
||||
utilizing an existing database connection to wrap around it.
|
||||
The Fastify instance passed to the function is the latest state of the **external
|
||||
Fastify instance** the plugin was declared on, allowing access to variables
|
||||
injected via [`decorate`](./Decorators.md) by preceding plugins according to the
|
||||
**order of registration**. This is useful if a plugin depends on changes made to
|
||||
the Fastify instance by a preceding plugin, such as utilizing an existing database
|
||||
connection.
|
||||
|
||||
Keep in mind that the Fastify instance passed on to the function is the same as
|
||||
the one that will be passed into the plugin, a copy of the external Fastify
|
||||
instance rather than a reference. Any usage of the instance will behave the same
|
||||
as it would if called within the plugins function i.e. if `decorate` is called,
|
||||
the decorated variables will be available within the plugins function unless it
|
||||
was wrapped with [`fastify-plugin`](https://github.com/fastify/fastify-plugin).
|
||||
Keep in mind that the Fastify instance passed to the function is the same as the
|
||||
one passed into the plugin, a copy of the external Fastify instance rather than
|
||||
a reference. Any usage of the instance will behave the same as it would if called
|
||||
within the plugin's function. For example, if `decorate` is called, the decorated
|
||||
variables will be available within the plugin's function unless it was wrapped
|
||||
with [`fastify-plugin`](https://github.com/fastify/fastify-plugin).
|
||||
|
||||
#### Route Prefixing option
|
||||
<a id="route-prefixing-option"></a>
|
||||
|
||||
If you pass an option with the key `prefix` with a `string` value, Fastify will
|
||||
use it to prefix all the routes inside the register, for more info check
|
||||
If an option with the key `prefix` and a `string` value is passed, Fastify will
|
||||
use it to prefix all the routes inside the register. For more info, check
|
||||
[here](./Routes.md#route-prefixing).
|
||||
|
||||
Be aware that if you wrap your routes with
|
||||
Be aware that if routes are wrapped with
|
||||
[`fastify-plugin`](https://github.com/fastify/fastify-plugin), this option will
|
||||
not work (there is a [workaround](./Routes.md#fastify-plugin) available).
|
||||
not work (see the [workaround](./Routes.md#fastify-plugin)).
|
||||
|
||||
#### Error handling
|
||||
<a id="error-handling"></a>
|
||||
|
||||
The error handling is done by
|
||||
[avvio](https://github.com/mcollina/avvio#error-handling).
|
||||
Error handling is done by [avvio](https://github.com/mcollina/avvio#error-handling).
|
||||
|
||||
As a general rule, it is highly recommended that you handle your errors in the
|
||||
next `after` or `ready` block, otherwise you will get them inside the `listen`
|
||||
callback.
|
||||
As a general rule, handle errors in the next `after` or `ready` block, otherwise
|
||||
they will be caught inside the `listen` callback.
|
||||
|
||||
```js
|
||||
fastify.register(require('my-plugin'))
|
||||
@@ -145,16 +137,15 @@ await fastify.ready()
|
||||
|
||||
await fastify.listen({ port: 3000 })
|
||||
```
|
||||
*Note: Using `await` when registering a plugin loads the plugin
|
||||
and the underlying dependency tree, "finalizing" the encapsulation process.
|
||||
Any mutations to the plugin after it and its dependencies have been
|
||||
loaded will not be reflected in the parent instance.*
|
||||
Using `await` when registering a plugin loads the plugin and its dependencies,
|
||||
"finalizing" the encapsulation process. Any mutations to the plugin after it and
|
||||
its dependencies have been loaded will not be reflected in the parent instance.
|
||||
|
||||
#### ESM support
|
||||
<a id="esm-support"></a>
|
||||
|
||||
ESM is supported as well from [Node.js
|
||||
`v13.3.0`](https://nodejs.org/api/esm.html) and above!
|
||||
ESM is supported from [Node.js `v13.3.0`](https://nodejs.org/api/esm.html)
|
||||
and above.
|
||||
|
||||
```js
|
||||
// main.mjs
|
||||
@@ -179,21 +170,29 @@ export default plugin
|
||||
### Create a plugin
|
||||
<a id="create-plugin"></a>
|
||||
|
||||
Creating a plugin is very easy, you just need to create a function that takes
|
||||
three parameters, the `fastify` instance, an `options` object, and the `done`
|
||||
callback.
|
||||
Creating a plugin is easy. Create a function that takes three parameters: the
|
||||
`fastify` instance, an `options` object, and the `done` callback. Alternatively,
|
||||
use an `async` function and omit the `done` callback.
|
||||
|
||||
Example:
|
||||
```js
|
||||
module.exports = function (fastify, opts, done) {
|
||||
module.exports = function callbackPlugin (fastify, opts, done) {
|
||||
fastify.decorate('utility', function () {})
|
||||
|
||||
fastify.get('/', handler)
|
||||
|
||||
done()
|
||||
}
|
||||
|
||||
// Or using async
|
||||
module.exports = async function asyncPlugin (fastify, opts) {
|
||||
fastify.decorate('utility', function () {})
|
||||
|
||||
fastify.get('/', handler)
|
||||
}
|
||||
```
|
||||
You can also use `register` inside another `register`:
|
||||
|
||||
`register` can also be used inside another `register`:
|
||||
```js
|
||||
module.exports = function (fastify, opts, done) {
|
||||
fastify.decorate('utility', function () {})
|
||||
@@ -205,28 +204,23 @@ module.exports = function (fastify, opts, done) {
|
||||
done()
|
||||
}
|
||||
```
|
||||
Sometimes, you will need to know when the server is about to close, for example,
|
||||
because you must close a connection to a database. To know when this is going to
|
||||
happen, you can use the [`'onClose'`](./Hooks.md#on-close) hook.
|
||||
|
||||
Do not forget that `register` will always create a new Fastify scope, if you do
|
||||
not need that, read the following section.
|
||||
Remember, `register` always creates a new Fastify scope. If this is not needed,
|
||||
read the following section.
|
||||
|
||||
### Handle the scope
|
||||
<a id="handle-scope"></a>
|
||||
|
||||
If you are using `register` only for extending the functionality of the server
|
||||
with [`decorate`](./Decorators.md), it is your responsibility to tell Fastify
|
||||
not to create a new scope. Otherwise, your changes will not be accessible by the
|
||||
user in the upper scope.
|
||||
If `register` is used only to extend server functionality with
|
||||
[`decorate`](./Decorators.md), tell Fastify not to create a new scope. Otherwise,
|
||||
changes will not be accessible in the upper scope.
|
||||
|
||||
You have two ways to tell Fastify to avoid the creation of a new context:
|
||||
There are two ways to avoid creating a new context:
|
||||
- Use the [`fastify-plugin`](https://github.com/fastify/fastify-plugin) module
|
||||
- Use the `'skip-override'` hidden property
|
||||
|
||||
We recommend using the `fastify-plugin` module, because it solves this problem
|
||||
for you, and you can pass a version range of Fastify as a parameter that your
|
||||
plugin will support.
|
||||
Using the `fastify-plugin` module is recommended, as it solves this problem and
|
||||
allows passing a version range of Fastify that the plugin will support:
|
||||
```js
|
||||
const fp = require('fastify-plugin')
|
||||
|
||||
@@ -238,10 +232,9 @@ module.exports = fp(function (fastify, opts, done) {
|
||||
Check the [`fastify-plugin`](https://github.com/fastify/fastify-plugin)
|
||||
documentation to learn more about how to use this module.
|
||||
|
||||
If you do not use the `fastify-plugin` module, you can use the `'skip-override'`
|
||||
hidden property, but we do not recommend it. If in the future the Fastify API
|
||||
changes it will be your responsibility to update the module, while if you use
|
||||
`fastify-plugin`, you can be sure about backward compatibility.
|
||||
If not using `fastify-plugin`, the `'skip-override'` hidden property can be used,
|
||||
but it is not recommended. Future Fastify API changes will be your responsibility
|
||||
to update, whilst `fastify-plugin` ensures backward compatibility.
|
||||
```js
|
||||
function yourPlugin (fastify, opts, done) {
|
||||
fastify.decorate('utility', function () {})
|
||||
|
||||
55
backend/node_modules/fastify/docs/Reference/Principles.md
generated
vendored
55
backend/node_modules/fastify/docs/Reference/Principles.md
generated
vendored
@@ -16,48 +16,41 @@ the following technical principles:
|
||||
|
||||
## "Zero" Overhead in Production
|
||||
|
||||
Fastify aims to implement its features by adding as minimal overhead to your
|
||||
application as possible.
|
||||
This is usually delivered by implementing fast algorithms and data structures,
|
||||
as well as JavaScript-specific features.
|
||||
Fastify aims to implement features with minimal overhead. This is achieved by
|
||||
using fast algorithms, data structures, and JavaScript-specific features.
|
||||
|
||||
Given that JavaScript does not offer zero-overhead data structures, this principle
|
||||
is at odds with providing a great developer experience and providing more features,
|
||||
as usually those cost some overhead.
|
||||
Since JavaScript does not offer zero-overhead data structures, this principle
|
||||
can conflict with providing a great developer experience and additional features,
|
||||
as these usually incur some overhead.
|
||||
|
||||
## "Good" Developer Experience
|
||||
|
||||
Fastify aims to provide the best developer experience at the performance point
|
||||
it is operating.
|
||||
It provides a great out-of-the-box experience that is flexible enough to be
|
||||
adapted to a variety of situations.
|
||||
Fastify aims to provide the best developer experience at its performance point.
|
||||
It offers a great out-of-the-box experience that is flexible enough to adapt to
|
||||
various situations.
|
||||
|
||||
As an example, this means that binary addons are forbidden because most JavaScript
|
||||
developers would not
|
||||
have access to a compiler.
|
||||
For example, binary addons are forbidden because most JavaScript developers do
|
||||
not have access to a compiler.
|
||||
|
||||
## Works great for small and big projects alike
|
||||
|
||||
We recognize that most applications start small and become more complex over time.
|
||||
Fastify aims to grow with
|
||||
the complexity of your application, providing advanced features to structure
|
||||
your codebase.
|
||||
Most applications start small and become more complex over time. Fastify aims to
|
||||
grow with this complexity, providing advanced features to structure codebases.
|
||||
|
||||
## Easy to migrate to microservices (or even serverless) and back
|
||||
|
||||
How you deploy your routes should not matter. The framework should "just work".
|
||||
Route deployment should not matter. The framework should "just work".
|
||||
|
||||
## Security and Data Validation
|
||||
|
||||
Your web framework is the first point of contact with untrusted data, and it
|
||||
needs to act as the first line of defense for your system.
|
||||
A web framework is the first point of contact with untrusted data and must act
|
||||
as the first line of defense for the system.
|
||||
|
||||
## If something could be a plugin, it likely should
|
||||
|
||||
We recognize that there are an infinite amount of use cases for an HTTP framework
|
||||
for Node.js. Catering to them in a single module would make the codebase unmaintainable.
|
||||
Therefore we provide hooks and options to allow you to customize the framework
|
||||
as you please.
|
||||
Recognizing the infinite use cases for an HTTP framework, catering to all in a
|
||||
single module would make the codebase unmaintainable. Therefore, hooks and
|
||||
options are provided to customize the framework as needed.
|
||||
|
||||
## Easily testable
|
||||
|
||||
@@ -65,14 +58,16 @@ Testing Fastify applications should be a first-class concern.
|
||||
|
||||
## Do not monkeypatch core
|
||||
|
||||
Monkeypatch Node.js APIs or installing globals that alter the behavior of the
|
||||
runtime makes building modular applications harder, and limit the use cases of Fastify.
|
||||
Other frameworks do this and we do not.
|
||||
Monkeypatching Node.js APIs or installing globals that alter the runtime makes
|
||||
building modular applications harder and limits Fastify's use cases. Other
|
||||
frameworks do this; Fastify does not.
|
||||
|
||||
## Semantic Versioning and Long Term Support
|
||||
|
||||
We provide a clear Long Term Support strategy so developers can know when to upgrade.
|
||||
A clear [Long Term Support strategy is provided](./LTS.md) to inform developers
|
||||
when to upgrade.
|
||||
|
||||
## Specification adherence
|
||||
|
||||
In doubt, we chose the strict behavior as defined by the relevant Specifications.
|
||||
In doubt, we chose the strict behavior as defined by the relevant
|
||||
Specifications.
|
||||
|
||||
205
backend/node_modules/fastify/docs/Reference/Reply.md
generated
vendored
205
backend/node_modules/fastify/docs/Reference/Reply.md
generated
vendored
@@ -11,15 +11,14 @@
|
||||
- [.headers(object)](#headersobject)
|
||||
- [.getHeader(key)](#getheaderkey)
|
||||
- [.getHeaders()](#getheaders)
|
||||
- [set-cookie](#set-cookie)
|
||||
- [.removeHeader(key)](#removeheaderkey)
|
||||
- [.hasHeader(key)](#hasheaderkey)
|
||||
- [.writeEarlyHints(hints, callback)](#writeearlyhintshints-callback)
|
||||
- [.trailer(key, function)](#trailerkey-function)
|
||||
- [.hasTrailer(key)](#hastrailerkey)
|
||||
- [.removeTrailer(key)](#removetrailerkey)
|
||||
- [.redirect(dest, [code ,])](#redirectdest--code)
|
||||
- [.callNotFound()](#callnotfound)
|
||||
- [.getResponseTime()](#getresponsetime)
|
||||
- [.type(contentType)](#typecontenttype)
|
||||
- [.getSerializationFunction(schema | httpStatus, [contentType])](#getserializationfunctionschema--httpstatus)
|
||||
- [.compileSerializationSchema(schema, [httpStatus], [contentType])](#compileserializationschemaschema-httpstatus)
|
||||
@@ -33,8 +32,9 @@
|
||||
- [Strings](#strings)
|
||||
- [Streams](#streams)
|
||||
- [Buffers](#buffers)
|
||||
- [ReadableStream](#send-readablestream)
|
||||
- [Response](#send-response)
|
||||
- [TypedArrays](#typedarrays)
|
||||
- [ReadableStream](#readablestream)
|
||||
- [Response](#response)
|
||||
- [Errors](#errors)
|
||||
- [Type of the final payload](#type-of-the-final-payload)
|
||||
- [Async-Await and Promises](#async-await-and-promises)
|
||||
@@ -58,6 +58,8 @@ since the request was received by Fastify.
|
||||
- `.getHeaders()` - Gets a shallow copy of all current response headers.
|
||||
- `.removeHeader(key)` - Remove the value of a previously set header.
|
||||
- `.hasHeader(name)` - Determine if a header has been set.
|
||||
- `.writeEarlyHints(hints, callback)` - Sends early hints to the user
|
||||
while the response is being prepared.
|
||||
- `.trailer(key, function)` - Sets a response trailer.
|
||||
- `.hasTrailer(key)` - Determine if a trailer has been set.
|
||||
- `.removeTrailer(key)` - Remove the value of a previously set trailer.
|
||||
@@ -68,16 +70,17 @@ since the request was received by Fastify.
|
||||
- `.serialize(payload)` - Serializes the specified payload using the default
|
||||
JSON serializer or using the custom serializer (if one is set) and returns the
|
||||
serialized payload.
|
||||
- `.getSerializationFunction(schema | httpStatus, [contentType])` - Returns the serialization
|
||||
function for the specified schema or http status, if any of either are set.
|
||||
- `.compileSerializationSchema(schema, [httpStatus], [contentType])` - Compiles
|
||||
the specified schema and returns a serialization function using the default
|
||||
(or customized) `SerializerCompiler`. The optional `httpStatus` is forwarded
|
||||
- `.getSerializationFunction(schema | httpStatus, [contentType])` - Returns the
|
||||
serialization function for the specified schema or http status, if any of
|
||||
either are set.
|
||||
- `.compileSerializationSchema(schema, [httpStatus], [contentType])` - Compiles
|
||||
the specified schema and returns a serialization function using the default
|
||||
(or customized) `SerializerCompiler`. The optional `httpStatus` is forwarded
|
||||
to the `SerializerCompiler` if provided, default to `undefined`.
|
||||
- `.serializeInput(data, schema, [,httpStatus], [contentType])` - Serializes
|
||||
- `.serializeInput(data, schema, [,httpStatus], [contentType])` - Serializes
|
||||
the specified data using the specified schema and returns the serialized payload.
|
||||
If the optional `httpStatus`, and `contentType` are provided, the function
|
||||
will use the serializer function given for that specific content type and
|
||||
If the optional `httpStatus`, and `contentType` are provided, the function
|
||||
will use the serializer function given for that specific content type and
|
||||
HTTP Status Code. Default to `undefined`.
|
||||
- `.serializer(function)` - Sets a custom serializer for the payload.
|
||||
- `.send(payload)` - Sends the payload to the user, could be a plain text, a
|
||||
@@ -86,13 +89,10 @@ since the request was received by Fastify.
|
||||
already been called.
|
||||
- `.hijack()` - interrupt the normal request lifecycle.
|
||||
- `.raw` - The
|
||||
[`http.ServerResponse`](https://nodejs.org/dist/latest-v14.x/docs/api/http.html#http_class_http_serverresponse)
|
||||
[`http.ServerResponse`](https://nodejs.org/dist/latest-v20.x/docs/api/http.html#http_class_http_serverresponse)
|
||||
from Node core.
|
||||
- `.log` - The logger instance of the incoming request.
|
||||
- `.request` - The incoming request.
|
||||
- `.getResponseTime()` - Deprecated, returns the amount of time passed
|
||||
since the request was received by Fastify.
|
||||
- `.context` - Deprecated, access the [Request's context](./Request.md) property.
|
||||
|
||||
```js
|
||||
fastify.get('/', options, function (request, reply) {
|
||||
@@ -104,14 +104,6 @@ fastify.get('/', options, function (request, reply) {
|
||||
})
|
||||
```
|
||||
|
||||
Additionally, `Reply` provides access to the context of the request:
|
||||
|
||||
```js
|
||||
fastify.get('/', {config: {foo: 'bar'}}, function (request, reply) {
|
||||
reply.send('handler config.foo = ' + reply.context.config.foo)
|
||||
})
|
||||
```
|
||||
|
||||
### .code(statusCode)
|
||||
<a id="code"></a>
|
||||
|
||||
@@ -123,9 +115,6 @@ If not set via `reply.code`, the resulting `statusCode` will be `200`.
|
||||
Invokes the custom response time getter to calculate the amount of time passed
|
||||
since the request was received by Fastify.
|
||||
|
||||
Note that unless this function is called in the [`onResponse`
|
||||
hook](./Hooks.md#onresponse) it will always return `0`.
|
||||
|
||||
```js
|
||||
const milliseconds = reply.elapsedTime
|
||||
```
|
||||
@@ -163,14 +152,14 @@ fastify.get('/', async function (req, rep) {
|
||||
Sets a response header. If the value is omitted or undefined, it is coerced to
|
||||
`''`.
|
||||
|
||||
> Note: the header's value must be properly encoded using
|
||||
> ℹ️ Note: The header's value must be properly encoded using
|
||||
> [`encodeURI`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI)
|
||||
> or similar modules such as
|
||||
> [`encodeurl`](https://www.npmjs.com/package/encodeurl). Invalid characters
|
||||
> will result in a 500 `TypeError` response.
|
||||
|
||||
For more information, see
|
||||
[`http.ServerResponse#setHeader`](https://nodejs.org/dist/latest-v14.x/docs/api/http.html#http_response_setheader_name_value).
|
||||
[`http.ServerResponse#setHeader`](https://nodejs.org/dist/latest-v20.x/docs/api/http.html#http_response_setheader_name_value).
|
||||
|
||||
- ### set-cookie
|
||||
<a id="set-cookie"></a>
|
||||
@@ -243,6 +232,27 @@ reply.getHeader('x-foo') // undefined
|
||||
|
||||
Returns a boolean indicating if the specified header has been set.
|
||||
|
||||
### .writeEarlyHints(hints, callback)
|
||||
<a id="writeEarlyHints"></a>
|
||||
|
||||
Sends early hints to the client. Early hints allow the client to
|
||||
start processing resources before the final response is sent.
|
||||
This can improve performance by allowing the client to preload
|
||||
or preconnect to resources while the server is still generating the response.
|
||||
|
||||
The hints parameter is an object containing the early hint key-value pairs.
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
reply.writeEarlyHints({
|
||||
Link: '</styles.css>; rel=preload; as=style'
|
||||
});
|
||||
```
|
||||
|
||||
The optional callback parameter is a function that will be called
|
||||
once the hint is sent or if an error occurs.
|
||||
|
||||
### .trailer(key, function)
|
||||
<a id="trailer"></a>
|
||||
|
||||
@@ -251,11 +261,11 @@ requires heavy resources to be sent after the `data`, for example,
|
||||
`Server-Timing` and `Etag`. It can ensure the client receives the response data
|
||||
as soon as possible.
|
||||
|
||||
*Note: The header `Transfer-Encoding: chunked` will be added once you use the
|
||||
trailer. It is a hard requirement for using trailer in Node.js.*
|
||||
> ℹ️ Note: The header `Transfer-Encoding: chunked` will be added once you use
|
||||
> the trailer. It is a hard requirement for using trailer in Node.js.
|
||||
|
||||
*Note: Any error passed to `done` callback will be ignored. If you interested
|
||||
in the error, you can turn on `debug` level logging.*
|
||||
> ℹ️ Note: Any error passed to `done` callback will be ignored. If you interested
|
||||
> in the error, you can turn on `debug` level logging.*
|
||||
|
||||
```js
|
||||
reply.trailer('server-timing', function() {
|
||||
@@ -270,14 +280,14 @@ const { createHash } = require('node:crypto')
|
||||
reply.trailer('content-md5', function(reply, payload, done) {
|
||||
const hash = createHash('md5')
|
||||
hash.update(payload)
|
||||
done(null, hash.disgest('hex'))
|
||||
done(null, hash.digest('hex'))
|
||||
})
|
||||
|
||||
// when you prefer async-await
|
||||
reply.trailer('content-md5', async function(reply, payload) {
|
||||
const hash = createHash('md5')
|
||||
hash.update(payload)
|
||||
return hash.disgest('hex')
|
||||
return hash.digest('hex')
|
||||
})
|
||||
```
|
||||
|
||||
@@ -305,7 +315,7 @@ reply.getTrailer('server-timing') // undefined
|
||||
Redirects a request to the specified URL, the status code is optional, default
|
||||
to `302` (if status code is not already set by calling `code`).
|
||||
|
||||
> Note: the input URL must be properly encoded using
|
||||
> ℹ️ Note: The input URL must be properly encoded using
|
||||
> [`encodeURI`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI)
|
||||
> or similar modules such as
|
||||
> [`encodeurl`](https://www.npmjs.com/package/encodeurl). Invalid URLs will
|
||||
@@ -343,22 +353,6 @@ hook specified in [`setNotFoundHandler`](./Server.md#set-not-found-handler).
|
||||
reply.callNotFound()
|
||||
```
|
||||
|
||||
### .getResponseTime()
|
||||
<a id="getResponseTime"></a>
|
||||
|
||||
Invokes the custom response time getter to calculate the amount of time passed
|
||||
since the request was received by Fastify.
|
||||
|
||||
Note that unless this function is called in the [`onResponse`
|
||||
hook](./Hooks.md#onresponse) it will always return `0`.
|
||||
|
||||
```js
|
||||
const milliseconds = reply.getResponseTime()
|
||||
```
|
||||
|
||||
*Note: This method is deprecated and will be removed in `fastify@5`.
|
||||
Use the [.elapsedTime](#elapsedtime) property instead.*
|
||||
|
||||
### .type(contentType)
|
||||
<a id="type"></a>
|
||||
|
||||
@@ -369,13 +363,14 @@ Sets the content type for the response. This is a shortcut for
|
||||
reply.type('text/html')
|
||||
```
|
||||
If the `Content-Type` has a JSON subtype, and the charset parameter is not set,
|
||||
`utf-8` will be used as the charset by default.
|
||||
`utf-8` will be used as the charset by default. For other content types, the
|
||||
charset must be set explicitly.
|
||||
|
||||
### .getSerializationFunction(schema | httpStatus, [contentType])
|
||||
<a id="getserializationfunction"></a>
|
||||
|
||||
By calling this function using a provided `schema` or `httpStatus`,
|
||||
and the optional `contentType`, it will return a `serialzation` function
|
||||
By calling this function using a provided `schema` or `httpStatus`,
|
||||
and the optional `contentType`, it will return a `serialization` function
|
||||
that can be used to serialize diverse inputs. It returns `undefined` if no
|
||||
serialization function was found using either of the provided inputs.
|
||||
|
||||
@@ -385,12 +380,12 @@ the serialization functions compiled by using `compileSerializationSchema`.
|
||||
```js
|
||||
const serialize = reply
|
||||
.getSerializationFunction({
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
})
|
||||
serialize({ foo: 'bar' }) // '{"foo":"bar"}'
|
||||
|
||||
@@ -419,8 +414,8 @@ The function returned (a.k.a. _serialization function_) returned is compiled
|
||||
by using the provided `SerializerCompiler`. Also this is cached by using
|
||||
a `WeakMap` for reducing compilation calls.
|
||||
|
||||
The optional parameters `httpStatus` and `contentType`, if provided,
|
||||
are forwarded directly to the `SerializerCompiler`, so it can be used
|
||||
The optional parameters `httpStatus` and `contentType`, if provided,
|
||||
are forwarded directly to the `SerializerCompiler`, so it can be used
|
||||
to compile the serialization function if a custom `SerializerCompiler` is used.
|
||||
|
||||
This heavily depends of the `schema#responses` attached to the route, or
|
||||
@@ -429,12 +424,12 @@ the serialization functions compiled by using `compileSerializationSchema`.
|
||||
```js
|
||||
const serialize = reply
|
||||
.compileSerializationSchema({
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
})
|
||||
serialize({ foo: 'bar' }) // '{"foo":"bar"}'
|
||||
|
||||
@@ -442,12 +437,12 @@ serialize({ foo: 'bar' }) // '{"foo":"bar"}'
|
||||
|
||||
const serialize = reply
|
||||
.compileSerializationSchema({
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}, 200)
|
||||
serialize({ foo: 'bar' }) // '{"foo":"bar"}'
|
||||
|
||||
@@ -493,7 +488,7 @@ const schema1 = {
|
||||
```
|
||||
|
||||
*Not*
|
||||
```js
|
||||
```js
|
||||
const serialize = reply.compileSerializationSchema(schema1)
|
||||
|
||||
// Later on...
|
||||
@@ -527,25 +522,25 @@ function will be compiled, forwarding the `httpStatus` and `contentType` if prov
|
||||
|
||||
```js
|
||||
reply
|
||||
.serializeInput({ foo: 'bar'}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
.serializeInput({ foo: 'bar'}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}) // '{"foo":"bar"}'
|
||||
|
||||
// or
|
||||
|
||||
reply
|
||||
.serializeInput({ foo: 'bar'}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}, 200) // '{"foo":"bar"}'
|
||||
|
||||
// or
|
||||
@@ -594,7 +589,7 @@ values.
|
||||
<a id="raw"></a>
|
||||
|
||||
This is the
|
||||
[`http.ServerResponse`](https://nodejs.org/dist/latest-v14.x/docs/api/http.html#http_class_http_serverresponse)
|
||||
[`http.ServerResponse`](https://nodejs.org/dist/latest-v20.x/docs/api/http.html#http_class_http_serverresponse)
|
||||
from Node core. Whilst you are using the Fastify `Reply` object, the use of
|
||||
`Reply.raw` functions is at your own risk as you are skipping all the Fastify
|
||||
logic of handling the HTTP response. e.g.:
|
||||
@@ -694,9 +689,13 @@ If you are sending a stream and you have not set a `'Content-Type'` header,
|
||||
As noted above, streams are considered to be pre-serialized, so they will be
|
||||
sent unmodified without response validation.
|
||||
|
||||
See special note about error handling for streams in
|
||||
[`setErrorHandler`](./Server.md#seterrorhandler).
|
||||
|
||||
```js
|
||||
const fs = require('node:fs')
|
||||
|
||||
fastify.get('/streams', function (request, reply) {
|
||||
const fs = require('node:fs')
|
||||
const stream = fs.createReadStream('some-file', 'utf8')
|
||||
reply.header('Content-Type', 'application/octet-stream')
|
||||
reply.send(stream)
|
||||
@@ -704,8 +703,9 @@ fastify.get('/streams', function (request, reply) {
|
||||
```
|
||||
When using async-await you will need to return or await the reply object:
|
||||
```js
|
||||
const fs = require('node:fs')
|
||||
|
||||
fastify.get('/streams', async function (request, reply) {
|
||||
const fs = require('node:fs')
|
||||
const stream = fs.createReadStream('some-file', 'utf8')
|
||||
reply.header('Content-Type', 'application/octet-stream')
|
||||
return reply.send(stream)
|
||||
@@ -718,11 +718,12 @@ fastify.get('/streams', async function (request, reply) {
|
||||
If you are sending a buffer and you have not set a `'Content-Type'` header,
|
||||
*send* will set it to `'application/octet-stream'`.
|
||||
|
||||
As noted above, Buffers are considered to be pre-serialized, so they will be
|
||||
As noted above, Buffers are considered to be pre-serialized, so they will be
|
||||
sent unmodified without response validation.
|
||||
|
||||
```js
|
||||
const fs = require('node:fs')
|
||||
|
||||
fastify.get('/streams', function (request, reply) {
|
||||
fs.readFile('some-file', (err, fileBuffer) => {
|
||||
reply.send(err || fileBuffer)
|
||||
@@ -733,6 +734,7 @@ fastify.get('/streams', function (request, reply) {
|
||||
When using async-await you will need to return or await the reply object:
|
||||
```js
|
||||
const fs = require('node:fs')
|
||||
|
||||
fastify.get('/streams', async function (request, reply) {
|
||||
fs.readFile('some-file', (err, fileBuffer) => {
|
||||
reply.send(err || fileBuffer)
|
||||
@@ -747,11 +749,12 @@ fastify.get('/streams', async function (request, reply) {
|
||||
`send` manages TypedArray like a Buffer, and sets the `'Content-Type'`
|
||||
header to `'application/octet-stream'` if not already set.
|
||||
|
||||
As noted above, TypedArray/Buffers are considered to be pre-serialized, so they
|
||||
As noted above, TypedArray/Buffers are considered to be pre-serialized, so they
|
||||
will be sent unmodified without response validation.
|
||||
|
||||
```js
|
||||
const fs = require('node:fs')
|
||||
|
||||
fastify.get('/streams', function (request, reply) {
|
||||
const typedArray = new Uint16Array(10)
|
||||
reply.send(typedArray)
|
||||
@@ -762,12 +765,13 @@ fastify.get('/streams', function (request, reply) {
|
||||
<a id="send-readablestream"></a>
|
||||
|
||||
`ReadableStream` will be treated as a node stream mentioned above,
|
||||
the content is considered to be pre-serialized, so they will be
|
||||
the content is considered to be pre-serialized, so they will be
|
||||
sent unmodified without response validation.
|
||||
|
||||
```js
|
||||
const fs = require('node:fs')
|
||||
const { ReadableStream } = require('node:stream/web')
|
||||
|
||||
fastify.get('/streams', function (request, reply) {
|
||||
const stream = fs.createReadStream('some-file')
|
||||
reply.header('Content-Type', 'application/octet-stream')
|
||||
@@ -780,7 +784,7 @@ fastify.get('/streams', function (request, reply) {
|
||||
|
||||
`Response` allows to manage the reply payload, status code and
|
||||
headers in one place. The payload provided inside `Response` is
|
||||
considered to be pre-serialized, so they will be sent unmodified
|
||||
considered to be pre-serialized, so they will be sent unmodified
|
||||
without response validation.
|
||||
|
||||
Please be aware when using `Response`, the status code and headers
|
||||
@@ -792,6 +796,7 @@ and may confuse when checking the `payload` in `onSend` hooks.
|
||||
```js
|
||||
const fs = require('node:fs')
|
||||
const { ReadableStream } = require('node:stream/web')
|
||||
|
||||
fastify.get('/streams', function (request, reply) {
|
||||
const stream = fs.createReadStream('some-file')
|
||||
const readableStream = ReadableStream.from(stream)
|
||||
@@ -822,8 +827,8 @@ automatically create an error structured as the following:
|
||||
You can add custom properties to the Error object, such as `headers`, that will
|
||||
be used to enhance the HTTP response.
|
||||
|
||||
*Note: If you are passing an error to `send` and the statusCode is less than
|
||||
400, Fastify will automatically set it at 500.*
|
||||
> ℹ️ Note: If you are passing an error to `send` and the statusCode is less than
|
||||
> 400, Fastify will automatically set it at 500.
|
||||
|
||||
Tip: you can simplify errors by using the
|
||||
[`http-errors`](https://npm.im/http-errors) module or
|
||||
@@ -870,14 +875,14 @@ fastify.get('/', {
|
||||
If you want to customize error handling, check out
|
||||
[`setErrorHandler`](./Server.md#seterrorhandler) API.
|
||||
|
||||
*Note: you are responsible for logging when customizing the error handler*
|
||||
> ℹ️ Note: you are responsible for logging when customizing the error handler.
|
||||
|
||||
API:
|
||||
|
||||
```js
|
||||
fastify.setErrorHandler(function (error, request, reply) {
|
||||
request.log.warn(error)
|
||||
var statusCode = error.statusCode >= 400 ? error.statusCode : 500
|
||||
const statusCode = error.statusCode >= 400 ? error.statusCode : 500
|
||||
reply
|
||||
.code(statusCode)
|
||||
.type('text/plain')
|
||||
|
||||
262
backend/node_modules/fastify/docs/Reference/Request.md
generated
vendored
262
backend/node_modules/fastify/docs/Reference/Request.md
generated
vendored
@@ -4,80 +4,71 @@
|
||||
The first parameter of the handler function is `Request`.
|
||||
|
||||
Request is a core Fastify object containing the following fields:
|
||||
- `query` - the parsed querystring, its format is specified by
|
||||
[`querystringParser`](./Server.md#querystringparser)
|
||||
- `body` - the request payload, see [Content-Type
|
||||
Parser](./ContentTypeParser.md) for details on what request payloads Fastify
|
||||
natively parses and how to support other content types
|
||||
- `params` - the params matching the URL
|
||||
- [`headers`](#headers) - the headers getter and setter
|
||||
- `raw` - the incoming HTTP request from Node core
|
||||
- `server` - The Fastify server instance, scoped to the current [encapsulation
|
||||
context](./Encapsulation.md)
|
||||
- `id` - the request ID
|
||||
- `log` - the logger instance of the incoming request
|
||||
- `ip` - the IP address of the incoming request
|
||||
- `ips` - an array of the IP addresses, ordered from closest to furthest, in the
|
||||
- `query` - The parsed querystring, its format is specified by
|
||||
[`querystringParser`](./Server.md#querystringparser).
|
||||
- `body` - The request payload, see [Content-Type Parser](./ContentTypeParser.md)
|
||||
for details on what request payloads Fastify natively parses and how to support
|
||||
other content types.
|
||||
- `params` - The params matching the URL.
|
||||
- [`headers`](#headers) - The headers getter and setter.
|
||||
- `raw` - The incoming HTTP request from Node core.
|
||||
- `server` - The Fastify server instance, scoped to the current
|
||||
[encapsulation context](./Encapsulation.md).
|
||||
- `id` - The request ID.
|
||||
- `log` - The logger instance of the incoming request.
|
||||
- `ip` - The IP address of the incoming request.
|
||||
- `ips` - An array of the IP addresses, ordered from closest to furthest, in the
|
||||
`X-Forwarded-For` header of the incoming request (only when the
|
||||
[`trustProxy`](./Server.md#factory-trust-proxy) option is enabled)
|
||||
- `hostname` - the host of the incoming request (derived from `X-Forwarded-Host`
|
||||
[`trustProxy`](./Server.md#factory-trust-proxy) option is enabled).
|
||||
- `host` - The host of the incoming request (derived from `X-Forwarded-Host`
|
||||
header when the [`trustProxy`](./Server.md#factory-trust-proxy) option is
|
||||
enabled). For HTTP/2 compatibility it returns `:authority` if no host header
|
||||
exists.
|
||||
- `protocol` - the protocol of the incoming request (`https` or `http`)
|
||||
- `method` - the method of the incoming request
|
||||
- `url` - the URL of the incoming request
|
||||
- `originalUrl` - similar to `url`, this allows you to access the
|
||||
original `url` in case of internal re-routing
|
||||
- `routerMethod` - Deprecated, use `request.routeOptions.method` instead. The
|
||||
method defined for the router that is handling the request
|
||||
- `routerPath` - Deprecated, use `request.routeOptions.url` instead. The
|
||||
path pattern defined for the router that is handling the request
|
||||
- `is404` - true if request is being handled by 404 handler, false if it is not
|
||||
- `connection` - Deprecated, use `socket` instead. The underlying connection of
|
||||
the incoming request.
|
||||
- `socket` - the underlying connection of the incoming request
|
||||
- `context` - Deprecated, use `request.routeOptions.config` instead.
|
||||
A Fastify internal object. You should not use
|
||||
it directly or modify it. It is useful to access one special key:
|
||||
enabled). For HTTP/2 compatibility, it returns `:authority` if no host header
|
||||
exists. The host header may return an empty string if `requireHostHeader` is
|
||||
`false`, not provided with HTTP/1.0, or removed by schema validation.
|
||||
- `hostname` - The hostname derived from the `host` property of the incoming request.
|
||||
- `port` - The port from the `host` property, which may refer to the port the
|
||||
server is listening on.
|
||||
- `protocol` - The protocol of the incoming request (`https` or `http`).
|
||||
- `method` - The method of the incoming request.
|
||||
- `url` - The URL of the incoming request.
|
||||
- `originalUrl` - Similar to `url`, allows access to the original `url` in
|
||||
case of internal re-routing.
|
||||
- `is404` - `true` if request is being handled by 404 handler, `false` otherwise.
|
||||
- `socket` - The underlying connection of the incoming request.
|
||||
- `context` - Deprecated, use `request.routeOptions.config` instead. A Fastify
|
||||
internal object. Do not use or modify it directly. It is useful to access one
|
||||
special key:
|
||||
- `context.config` - The route [`config`](./Routes.md#routes-config) object.
|
||||
- `routeSchema` - Deprecated, use `request.routeOptions.schema` instead. The
|
||||
scheme definition set for the router that is handling the request
|
||||
- `routeConfig` - Deprecated, use `request.routeOptions.config` instead. The
|
||||
route [`config`](./Routes.md#routes-config)
|
||||
object.
|
||||
- `routeOptions` - The route [`option`](./Routes.md#routes-options) object
|
||||
- `bodyLimit` - either server limit or route limit
|
||||
- `config` - the [`config`](./Routes.md#routes-config) object for this route
|
||||
- `method` - the http method for the route
|
||||
- `url` - the path of the URL to match this route
|
||||
- `handler` - the handler for this route
|
||||
- `attachValidation` - attach `validationError` to request
|
||||
(if there is a schema defined)
|
||||
- `logLevel` - log level defined for this route
|
||||
- `schema` - the JSON schemas definition for this route
|
||||
- `version` - a semver compatible string that defines the version of the endpoint
|
||||
- `exposeHeadRoute` - creates a sibling HEAD route for any GET routes
|
||||
- `prefixTrailingSlash` - string used to determine how to handle passing /
|
||||
- `routeOptions` - The route [`option`](./Routes.md#routes-options) object.
|
||||
- `bodyLimit` - Either server limit or route limit.
|
||||
- `config` - The [`config`](./Routes.md#routes-config) object for this route.
|
||||
- `method` - The HTTP method for the route.
|
||||
- `url` - The path of the URL to match this route.
|
||||
- `handler` - The handler for this route.
|
||||
- `attachValidation` - Attach `validationError` to request (if there is
|
||||
a schema defined).
|
||||
- `logLevel` - Log level defined for this route.
|
||||
- `schema` - The JSON schemas definition for this route.
|
||||
- `version` - A semver compatible string that defines the version of the endpoint.
|
||||
- `exposeHeadRoute` - Creates a sibling HEAD route for any GET routes.
|
||||
- `prefixTrailingSlash` - String used to determine how to handle passing `/`
|
||||
as a route with a prefix.
|
||||
- [.getValidationFunction(schema | httpPart)](#getvalidationfunction) -
|
||||
Returns a validation function for the specified schema or http part,
|
||||
if any of either are set or cached.
|
||||
- [.getValidationFunction(schema | httpPart)](#getvalidationfunction) -
|
||||
Returns a validation function for the specified schema or HTTP part, if
|
||||
set or cached.
|
||||
- [.compileValidationSchema(schema, [httpPart])](#compilevalidationschema) -
|
||||
Compiles the specified schema and returns a validation function
|
||||
using the default (or customized) `ValidationCompiler`.
|
||||
The optional `httpPart` is forwarded to the `ValidationCompiler`
|
||||
if provided, defaults to `null`.
|
||||
Compiles the specified schema and returns a validation function using the
|
||||
default (or customized) `ValidationCompiler`. The optional `httpPart` is
|
||||
forwarded to the `ValidationCompiler` if provided, defaults to `null`.
|
||||
- [.validateInput(data, schema | httpPart, [httpPart])](#validate) -
|
||||
Validates the specified input by using the specified
|
||||
schema and returns the serialized payload. If the optional
|
||||
`httpPart` is provided, the function will use the serializer
|
||||
function given for that HTTP Status Code. Defaults to `null`.
|
||||
Validates the input using the specified schema and returns the serialized
|
||||
payload. If `httpPart` is provided, the function uses the serializer for
|
||||
that HTTP Status Code. Defaults to `null`.
|
||||
|
||||
### Headers
|
||||
|
||||
The `request.headers` is a getter that returns an Object with the headers of the
|
||||
incoming request. You can set custom headers like this:
|
||||
The `request.headers` is a getter that returns an object with the headers of the
|
||||
incoming request. Set custom headers as follows:
|
||||
|
||||
```js
|
||||
request.headers = {
|
||||
@@ -86,12 +77,15 @@ request.headers = {
|
||||
}
|
||||
```
|
||||
|
||||
This operation will add to the request headers the new values that can be read
|
||||
calling `request.headers.bar`. Moreover, you can still access the standard
|
||||
request's headers with the `request.raw.headers` property.
|
||||
This operation adds new values to the request headers, accessible via
|
||||
`request.headers.bar`. Standard request headers remain accessible via
|
||||
`request.raw.headers`.
|
||||
|
||||
> Note: For performance reason on `not found` route, you may see that we will
|
||||
add an extra property `Symbol('fastify.RequestAcceptVersion')` on the headers.
|
||||
For performance reasons, `Symbol('fastify.RequestAcceptVersion')` may be added
|
||||
to headers on `not found` routes.
|
||||
|
||||
> ℹ️ Note: Schema validation may mutate the `request.headers` and
|
||||
> `request.raw.headers` objects, causing the headers to become empty.
|
||||
|
||||
```js
|
||||
fastify.post('/:params', options, function (request, reply) {
|
||||
@@ -104,7 +98,9 @@ fastify.post('/:params', options, function (request, reply) {
|
||||
console.log(request.id)
|
||||
console.log(request.ip)
|
||||
console.log(request.ips)
|
||||
console.log(request.host)
|
||||
console.log(request.hostname)
|
||||
console.log(request.port)
|
||||
console.log(request.protocol)
|
||||
console.log(request.url)
|
||||
console.log(request.routeOptions.method)
|
||||
@@ -123,23 +119,22 @@ fastify.post('/:params', options, function (request, reply) {
|
||||
### .getValidationFunction(schema | httpPart)
|
||||
<a id="getvalidationfunction"></a>
|
||||
|
||||
By calling this function using a provided `schema` or `httpPart`,
|
||||
it will return a `validation` function that can be used to
|
||||
validate diverse inputs. It returns `undefined` if no
|
||||
serialization function was found using either of the provided inputs.
|
||||
By calling this function with a provided `schema` or `httpPart`, it returns a
|
||||
`validation` function to validate diverse inputs. It returns `undefined` if no
|
||||
serialization function is found using the provided inputs.
|
||||
|
||||
This function has property errors. Errors encountered during the last validation
|
||||
are assigned to errors
|
||||
This function has an `errors` property. Errors encountered during the last
|
||||
validation are assigned to `errors`.
|
||||
|
||||
```js
|
||||
const validate = request
|
||||
.getValidationFunction({
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
})
|
||||
console.log(validate({ foo: 'bar' })) // true
|
||||
console.log(validate.errors) // null
|
||||
@@ -152,34 +147,33 @@ console.log(validate({ foo: 0.5 })) // false
|
||||
console.log(validate.errors) // validation errors
|
||||
```
|
||||
|
||||
See [.compileValidationSchema(schema, [httpStatus])](#compilevalidationschema)
|
||||
for more information on how to compile validation function.
|
||||
See [.compileValidationSchema(schema, [httpStatus])](#compileValidationSchema)
|
||||
for more information on compiling validation schemas.
|
||||
|
||||
### .compileValidationSchema(schema, [httpPart])
|
||||
<a id="compilevalidationschema"></a>
|
||||
|
||||
This function will compile a validation schema and
|
||||
return a function that can be used to validate data.
|
||||
The function returned (a.k.a. _validation function_) is compiled
|
||||
by using the provided [`SchemaController#ValidationCompiler`](./Server.md#schema-controller).
|
||||
A `WeakMap` is used to cached this, reducing compilation calls.
|
||||
This function compiles a validation schema and returns a function to validate data.
|
||||
The returned function (a.k.a. _validation function_) is compiled using the provided
|
||||
[`SchemaController#ValidationCompiler`](./Server.md#schema-controller). A `WeakMap`
|
||||
is used to cache this, reducing compilation calls.
|
||||
|
||||
The optional parameter `httpPart`, if provided, is forwarded directly
|
||||
the `ValidationCompiler`, so it can be used to compile the validation
|
||||
function if a custom `ValidationCompiler` is provided for the route.
|
||||
The optional parameter `httpPart`, if provided, is forwarded to the
|
||||
`ValidationCompiler`, allowing it to compile the validation function if a custom
|
||||
`ValidationCompiler` is provided for the route.
|
||||
|
||||
This function has property errors. Errors encountered during the last validation
|
||||
are assigned to errors
|
||||
This function has an `errors` property. Errors encountered during the last
|
||||
validation are assigned to `errors`.
|
||||
|
||||
```js
|
||||
const validate = request
|
||||
.compileValidationSchema({
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
})
|
||||
console.log(validate({ foo: 'bar' })) // true
|
||||
console.log(validate.errors) // null
|
||||
@@ -188,27 +182,24 @@ console.log(validate.errors) // null
|
||||
|
||||
const validate = request
|
||||
.compileValidationSchema({
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}, 200)
|
||||
console.log(validate({ hello: 'world' })) // false
|
||||
console.log(validate.errors) // validation errors
|
||||
```
|
||||
|
||||
Note that you should be careful when using this function, as it will cache
|
||||
the compiled validation functions based on the schema provided. If the
|
||||
schemas provided are mutated or changed, the validation functions will not
|
||||
detect that the schema has been altered and for instance it will reuse the
|
||||
previously compiled validation function, as the cache is based on
|
||||
the reference of the schema (Object) previously provided.
|
||||
Be careful when using this function, as it caches compiled validation functions
|
||||
based on the provided schema. If schemas are mutated or changed, the validation
|
||||
functions will not detect the alterations and will reuse the previously compiled
|
||||
validation function, as the cache is based on the schema's reference.
|
||||
|
||||
If there is a need to change the properties of a schema, always opt to create
|
||||
a totally new schema (object), otherwise the implementation will not benefit from
|
||||
the cache mechanism.
|
||||
If schema properties need to be changed, create a new schema object to benefit
|
||||
from the cache mechanism.
|
||||
|
||||
Using the following schema as an example:
|
||||
```js
|
||||
@@ -223,7 +214,7 @@ const schema1 = {
|
||||
```
|
||||
|
||||
*Not*
|
||||
```js
|
||||
```js
|
||||
const validate = request.compileValidationSchema(schema1)
|
||||
|
||||
// Later on...
|
||||
@@ -246,37 +237,36 @@ const newValidate = request.compileValidationSchema(newSchema)
|
||||
console.log(newValidate === validate) // false
|
||||
```
|
||||
|
||||
### .validateInput(data, [schema | httpStatus], [httpStatus])
|
||||
### .validateInput(data, [schema | httpPart], [httpPart])
|
||||
<a id="validate"></a>
|
||||
|
||||
This function will validate the input based on the provided schema,
|
||||
or HTTP part passed. If both are provided, the `httpPart` parameter
|
||||
will take precedence.
|
||||
This function validates the input based on the provided schema or HTTP part. If
|
||||
both are provided, the `httpPart` parameter takes precedence.
|
||||
|
||||
If there is not a validation function for a given `schema`, a new validation
|
||||
function will be compiled, forwarding the `httpPart` if provided.
|
||||
If no validation function exists for a given `schema`, a new validation function
|
||||
will be compiled, forwarding the `httpPart` if provided.
|
||||
|
||||
```js
|
||||
request
|
||||
.validateInput({ foo: 'bar'}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
.validateInput({ foo: 'bar'}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}) // true
|
||||
|
||||
// or
|
||||
|
||||
request
|
||||
.validateInput({ foo: 'bar'}, {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}, 'body') // true
|
||||
|
||||
// or
|
||||
@@ -286,4 +276,4 @@ request
|
||||
```
|
||||
|
||||
See [.compileValidationSchema(schema, [httpStatus])](#compileValidationSchema)
|
||||
for more information on how to compile validation schemas.
|
||||
for more information on compiling validation schemas.
|
||||
|
||||
319
backend/node_modules/fastify/docs/Reference/Routes.md
generated
vendored
319
backend/node_modules/fastify/docs/Reference/Routes.md
generated
vendored
@@ -2,9 +2,8 @@
|
||||
|
||||
## Routes
|
||||
|
||||
The route methods will configure the endpoints of your application. You have two
|
||||
ways to declare a route with Fastify: the shorthand method and the full
|
||||
declaration.
|
||||
The route methods configure the endpoints of the application. Routes can be
|
||||
declared using the shorthand method or the full declaration.
|
||||
|
||||
- [Full declaration](#full-declaration)
|
||||
- [Routes options](#routes-options)
|
||||
@@ -32,10 +31,9 @@ fastify.route(options)
|
||||
### Routes options
|
||||
<a id="options"></a>
|
||||
|
||||
* `method`: currently it supports `'DELETE'`, `'GET'`, `'HEAD'`, `'PATCH'`,
|
||||
`'POST'`, `'PUT'`, `'OPTIONS'`, `'SEARCH'`, `'TRACE'`, `'PROPFIND'`,
|
||||
`'PROPPATCH'`, `'MKCOL'`, `'COPY'`, `'MOVE'`, `'LOCK'`, `'UNLOCK'`,
|
||||
`'REPORT'` and `'MKCALENDAR'`.
|
||||
* `method`: currently it supports `GET`, `HEAD`, `TRACE`, `DELETE`,
|
||||
`OPTIONS`, `PATCH`, `PUT` and `POST`. To accept more methods,
|
||||
the [`addHttpMethod`](./Server.md#addHttpMethod) must be used.
|
||||
It could also be an array of methods.
|
||||
* `url`: the path of the URL to match this route (alias: `path`).
|
||||
* `schema`: an object containing the schemas for the request and response. They
|
||||
@@ -43,8 +41,7 @@ fastify.route(options)
|
||||
[here](./Validation-and-Serialization.md) for more info.
|
||||
|
||||
* `body`: validates the body of the request if it is a POST, PUT, PATCH,
|
||||
TRACE, SEARCH, PROPFIND, PROPPATCH, COPY, MOVE, MKCOL, REPORT, MKCALENDAR
|
||||
or LOCK method.
|
||||
TRACE, SEARCH, PROPFIND, PROPPATCH or LOCK method.
|
||||
* `querystring` or `query`: validates the querystring. This can be a complete
|
||||
JSON Schema object, with the property `type` of `object` and `properties`
|
||||
object of parameters, or simply the values of what would be contained in the
|
||||
@@ -62,8 +59,9 @@ fastify.route(options)
|
||||
one.
|
||||
* `onRequest(request, reply, done)`: a [function](./Hooks.md#onrequest) called
|
||||
as soon as a request is received, it could also be an array of functions.
|
||||
* `preParsing(request, reply, done)`: a [function](./Hooks.md#preparsing) called
|
||||
before parsing the request, it could also be an array of functions.
|
||||
* `preParsing(request, reply, payload, done)`: a
|
||||
[function](./Hooks.md#preparsing) called before parsing the request, it could
|
||||
also be an array of functions.
|
||||
* `preValidation(request, reply, done)`: a [function](./Hooks.md#prevalidation)
|
||||
called after the shared `preValidation` hooks, useful if you need to perform
|
||||
authentication at route level for example, it could also be an array of
|
||||
@@ -95,16 +93,16 @@ fastify.route(options)
|
||||
* `childLoggerFactory(logger, binding, opts, rawReq)`: a custom factory function
|
||||
that will be called to produce a child logger instance for every request.
|
||||
See [`childLoggerFactory`](./Server.md#childloggerfactory) for more info.
|
||||
Overrides the default logger factory, and anything set by
|
||||
Overrides the default logger factory, and anything set by
|
||||
[`setChildLoggerFactory`](./Server.md#setchildloggerfactory), for requests to
|
||||
the route. To access the default factory, you can access
|
||||
the route. To access the default factory, you can access
|
||||
`instance.childLoggerFactory`. Note that this will point to Fastify's default
|
||||
`childLoggerFactory` only if a plugin hasn't overridden it already.
|
||||
* `validatorCompiler({ schema, method, url, httpPart })`: function that builds
|
||||
schemas for request validations. See the [Validation and
|
||||
Serialization](./Validation-and-Serialization.md#schema-validator)
|
||||
documentation.
|
||||
* `serializerCompiler({ { schema, method, url, httpStatus, contentType } })`:
|
||||
* `serializerCompiler({ { schema, method, url, httpStatus, contentType } })`:
|
||||
function that builds schemas for response serialization. See the [Validation and
|
||||
Serialization](./Validation-and-Serialization.md#schema-serializer)
|
||||
documentation.
|
||||
@@ -123,8 +121,8 @@ fastify.route(options)
|
||||
* `version`: a [semver](https://semver.org/) compatible string that defined the
|
||||
version of the endpoint. [Example](#version-constraints).
|
||||
* `constraints`: defines route restrictions based on request properties or
|
||||
values, enabling customized matching using
|
||||
[find-my-way](https://github.com/delvedor/find-my-way) constraints. Includes
|
||||
values, enabling customized matching using
|
||||
[find-my-way](https://github.com/delvedor/find-my-way) constraints. Includes
|
||||
built-in `version` and `host` constraints, with support for custom constraint
|
||||
strategies.
|
||||
* `prefixTrailingSlash`: string used to determine how to handle passing `/` as a
|
||||
@@ -140,11 +138,11 @@ fastify.route(options)
|
||||
|
||||
* `reply` is defined in [Reply](./Reply.md).
|
||||
|
||||
**Notice:** The documentation of `onRequest`, `preParsing`, `preValidation`,
|
||||
`preHandler`, `preSerialization`, `onSend`, and `onResponse` are described in
|
||||
more detail in [Hooks](./Hooks.md). Additionally, to send a response before the
|
||||
request is handled by the `handler` please refer to [Respond to a request from a
|
||||
hook](./Hooks.md#respond-to-a-request-from-a-hook).
|
||||
> ℹ️ Note: The documentation for `onRequest`, `preParsing`, `preValidation`,
|
||||
> `preHandler`, `preSerialization`, `onSend`, and `onResponse` is detailed in
|
||||
> [Hooks](./Hooks.md). To send a response before the request is handled by the
|
||||
> `handler`, see [Respond to a request from
|
||||
> a hook](./Hooks.md#respond-to-a-request-from-a-hook).
|
||||
|
||||
Example:
|
||||
```js
|
||||
@@ -153,8 +151,11 @@ fastify.route({
|
||||
url: '/',
|
||||
schema: {
|
||||
querystring: {
|
||||
name: { type: 'string' },
|
||||
excitement: { type: 'integer' }
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
excitement: { type: 'integer' }
|
||||
}
|
||||
},
|
||||
response: {
|
||||
200: {
|
||||
@@ -233,17 +234,17 @@ const opts = {
|
||||
fastify.get('/', opts)
|
||||
```
|
||||
|
||||
> Note: if the handler is specified in both the `options` and as the third
|
||||
> parameter to the shortcut method then throws a duplicate `handler` error.
|
||||
> ℹ️ Note: Specifying the handler in both `options` and as the third parameter to
|
||||
> the shortcut method throws a duplicate `handler` error.
|
||||
|
||||
### Url building
|
||||
<a id="url-building"></a>
|
||||
|
||||
Fastify supports both static and dynamic URLs.
|
||||
|
||||
To register a **parametric** path, use the *colon* before the parameter name.
|
||||
For **wildcard**, use the *star*. *Remember that static routes are always
|
||||
checked before parametric and wildcard.*
|
||||
To register a **parametric** path, use a *colon* before the parameter name. For
|
||||
**wildcard**, use a *star*. Static routes are always checked before parametric
|
||||
and wildcard routes.
|
||||
|
||||
```js
|
||||
// parametric
|
||||
@@ -265,9 +266,8 @@ fastify.get('/example/:userId/:secretToken', function (request, reply) {
|
||||
fastify.get('/example/*', function (request, reply) {})
|
||||
```
|
||||
|
||||
Regular expression routes are supported as well, but be aware that you have to
|
||||
escape slashes. Take note that RegExp is also very expensive in terms of
|
||||
performance!
|
||||
Regular expression routes are supported, but slashes must be escaped.
|
||||
Take note that RegExp is also very expensive in terms of performance!
|
||||
```js
|
||||
// parametric with regexp
|
||||
fastify.get('/example/:file(^\\d+).png', function (request, reply) {
|
||||
@@ -305,24 +305,24 @@ fastify.get('/example/at/:hour(^\\d{2})h:minute(^\\d{2})m', function (request, r
|
||||
In this case as parameter separator it is possible to use whatever character is
|
||||
not matched by the regular expression.
|
||||
|
||||
The last parameter can be made optional if you add a question mark ("?") to the
|
||||
end of the parameters name.
|
||||
The last parameter can be made optional by adding a question mark ("?") to the
|
||||
end of the parameter name.
|
||||
```js
|
||||
fastify.get('/example/posts/:id?', function (request, reply) {
|
||||
const { id } = request.params;
|
||||
// your code here
|
||||
})
|
||||
```
|
||||
In this case you can request `/example/posts` as well as `/example/posts/1`.
|
||||
The optional param will be undefined if not specified.
|
||||
In this case, `/example/posts` and `/example/posts/1` are both valid. The
|
||||
optional param will be `undefined` if not specified.
|
||||
|
||||
Having a route with multiple parameters may negatively affect performance, so
|
||||
prefer a single parameter approach whenever possible, especially on routes that
|
||||
are on the hot path of your application. If you are interested in how we handle
|
||||
the routing, check out [find-my-way](https://github.com/delvedor/find-my-way).
|
||||
Having a route with multiple parameters may negatively affect performance.
|
||||
Prefer a single parameter approach, especially on routes that are on the hot
|
||||
path of your application. For more details, see
|
||||
[find-my-way](https://github.com/delvedor/find-my-way).
|
||||
|
||||
If you want a path containing a colon without declaring a parameter, use a
|
||||
double colon. For example:
|
||||
To include a colon in a path without declaring a parameter, use a double colon.
|
||||
For example:
|
||||
```js
|
||||
fastify.post('/name::verb') // will be interpreted as /name:verb
|
||||
```
|
||||
@@ -333,23 +333,23 @@ fastify.post('/name::verb') // will be interpreted as /name:verb
|
||||
Are you an `async/await` user? We have you covered!
|
||||
```js
|
||||
fastify.get('/', options, async function (request, reply) {
|
||||
var data = await getData()
|
||||
var processed = await processData(data)
|
||||
const data = await getData()
|
||||
const processed = await processData(data)
|
||||
return processed
|
||||
})
|
||||
```
|
||||
|
||||
As you can see, we are not calling `reply.send` to send back the data to the
|
||||
user. You just need to return the body and you are done!
|
||||
As shown, `reply.send` is not called to send data back to the user. Simply
|
||||
return the body and you are done!
|
||||
|
||||
If you need it you can also send back the data to the user with `reply.send`. In
|
||||
this case do not forget to `return reply` or `await reply` in your `async`
|
||||
handler or you will introduce a race condition in certain situations.
|
||||
If needed, you can also send data back with `reply.send`. In this case, do not
|
||||
forget to `return reply` or `await reply` in your `async` handler to avoid race
|
||||
conditions.
|
||||
|
||||
```js
|
||||
fastify.get('/', options, async function (request, reply) {
|
||||
var data = await getData()
|
||||
var processed = await processData(data)
|
||||
const data = await getData()
|
||||
const processed = await processData(data)
|
||||
return reply.send(processed)
|
||||
})
|
||||
```
|
||||
@@ -377,48 +377,42 @@ fastify.get('/', options, async function (request, reply) {
|
||||
})
|
||||
```
|
||||
|
||||
**Warning:**
|
||||
* When using both `return value` and `reply.send(value)` at the same time, the
|
||||
first one that happens takes precedence, the second value will be discarded,
|
||||
and a *warn* log will also be emitted because you tried to send a response
|
||||
twice.
|
||||
* Calling `reply.send()` outside of the promise is possible but requires special
|
||||
attention. For more details read [promise-resolution](#promise-resolution).
|
||||
* You cannot return `undefined`. For more details read
|
||||
[promise-resolution](#promise-resolution).
|
||||
> ⚠ Warning:
|
||||
> * When using both `return value` and `reply.send(value)`, the first one takes
|
||||
> precedence, the second is discarded, and a *warn* log is emitted.
|
||||
> * Calling `reply.send()` outside of the promise is possible but requires special
|
||||
> attention. See [promise-resolution](#promise-resolution).
|
||||
> * `undefined` cannot be returned. See [promise-resolution](#promise-resolution).
|
||||
|
||||
### Promise resolution
|
||||
<a id="promise-resolution"></a>
|
||||
|
||||
If your handler is an `async` function or returns a promise, you should be aware
|
||||
of the special behavior that is necessary to support the callback and promise
|
||||
control-flow. When the handler's promise is resolved, the reply will be
|
||||
automatically sent with its value unless you explicitly await or return `reply`
|
||||
in your handler.
|
||||
If the handler is an `async` function or returns a promise, be aware of the
|
||||
special behavior to support callback and promise control-flow. When the
|
||||
handler's promise resolves, the reply is automatically sent with its value
|
||||
unless you explicitly await or return `reply` in the handler.
|
||||
|
||||
1. If you want to use `async/await` or promises but respond with a value with
|
||||
`reply.send`:
|
||||
1. If using `async/await` or promises but responding with `reply.send`:
|
||||
- **Do** `return reply` / `await reply`.
|
||||
- **Do not** forget to call `reply.send`.
|
||||
2. If you want to use `async/await` or promises:
|
||||
2. If using `async/await` or promises:
|
||||
- **Do not** use `reply.send`.
|
||||
- **Do** return the value that you want to send.
|
||||
- **Do** return the value to send.
|
||||
|
||||
In this way, we can support both `callback-style` and `async-await`, with the
|
||||
minimum trade-off. Despite so much freedom we highly recommend going with only
|
||||
one style because error handling should be handled in a consistent way within
|
||||
your application.
|
||||
This approach supports both `callback-style` and `async-await` with minimal
|
||||
trade-off. However, it is recommended to use only one style for consistent
|
||||
error handling within your application.
|
||||
|
||||
**Notice**: Every async function returns a promise by itself.
|
||||
> ℹ️ Note: Every async function returns a promise by itself.
|
||||
|
||||
### Route Prefixing
|
||||
<a id="route-prefixing"></a>
|
||||
|
||||
Sometimes you need to maintain two or more different versions of the same API; a
|
||||
classic approach is to prefix all the routes with the API version number,
|
||||
`/v1/user` for example. Fastify offers you a fast and smart way to create
|
||||
different versions of the same API without changing all the route names by hand,
|
||||
*route prefixing*. Let's see how it works:
|
||||
Sometimes maintaining multiple versions of the same API is necessary. A common
|
||||
approach is to prefix routes with the API version number, e.g., `/v1/user`.
|
||||
Fastify offers a fast and smart way to create different versions of the same API
|
||||
without changing all the route names by hand, called *route prefixing*. Here is
|
||||
how it works:
|
||||
|
||||
```js
|
||||
// server.js
|
||||
@@ -445,19 +439,18 @@ module.exports = function (fastify, opts, done) {
|
||||
done()
|
||||
}
|
||||
```
|
||||
Fastify will not complain because you are using the same name for two different
|
||||
routes, because at compilation time it will handle the prefix automatically
|
||||
*(this also means that the performance will not be affected at all!)*.
|
||||
Fastify will not complain about using the same name for two different routes
|
||||
because it handles the prefix automatically at compilation time. This ensures
|
||||
performance is not affected.
|
||||
|
||||
Now your clients will have access to the following routes:
|
||||
Now clients will have access to the following routes:
|
||||
- `/v1/user`
|
||||
- `/v2/user`
|
||||
|
||||
You can do this as many times as you want, it also works for nested `register`,
|
||||
and route parameters are supported as well.
|
||||
This can be done multiple times and works for nested `register`. Route
|
||||
parameters are also supported.
|
||||
|
||||
In case you want to use prefix for all of your routes, you can put them inside a
|
||||
plugin:
|
||||
To use a prefix for all routes, place them inside a plugin:
|
||||
|
||||
```js
|
||||
const fastify = require('fastify')()
|
||||
@@ -469,23 +462,21 @@ const route = {
|
||||
schema: {},
|
||||
}
|
||||
|
||||
fastify.register(function(app, _, done) {
|
||||
fastify.register(function (app, _, done) {
|
||||
app.get('/users', () => {})
|
||||
app.route(route)
|
||||
|
||||
done()
|
||||
}, { prefix: '/v1' }) // global route prefix
|
||||
|
||||
await fastify.listen({ port: 0 })
|
||||
await fastify.listen({ port: 3000 })
|
||||
```
|
||||
|
||||
### Route Prefixing and fastify-plugin
|
||||
<a id="fastify-plugin"></a>
|
||||
|
||||
Be aware that if you use
|
||||
[`fastify-plugin`](https://github.com/fastify/fastify-plugin) for wrapping your
|
||||
routes, this option will not work. You can still make it work by wrapping a
|
||||
plugin in a plugin, e. g.:
|
||||
If using [`fastify-plugin`](https://github.com/fastify/fastify-plugin) to wrap
|
||||
routes, this option will not work. To make it work, wrap a plugin in a plugin:
|
||||
```js
|
||||
const fp = require('fastify-plugin')
|
||||
const routes = require('./lib/routes')
|
||||
@@ -501,27 +492,23 @@ module.exports = fp(async function (app, opts) {
|
||||
|
||||
#### Handling of / route inside prefixed plugins
|
||||
|
||||
The `/` route has different behavior depending on if the prefix ends with `/` or
|
||||
not. As an example, if we consider a prefix `/something/`, adding a `/` route
|
||||
will only match `/something/`. If we consider a prefix `/something`, adding a
|
||||
`/` route will match both `/something` and `/something/`.
|
||||
The `/` route behaves differently based on whether the prefix ends with `/`.
|
||||
For example, with a prefix `/something/`, adding a `/` route matches only
|
||||
`/something/`. With a prefix `/something`, adding a `/` route matches both
|
||||
`/something` and `/something/`.
|
||||
|
||||
See the `prefixTrailingSlash` route option above to change this behavior.
|
||||
|
||||
### Custom Log Level
|
||||
<a id="custom-log-level"></a>
|
||||
|
||||
You might need different log levels in your routes; Fastify achieves this in a
|
||||
very straightforward way.
|
||||
Different log levels can be set for routes in Fastify by passing the `logLevel`
|
||||
option to the plugin or route with the desired
|
||||
[value](https://github.com/pinojs/pino/blob/master/docs/api.md#level-string).
|
||||
|
||||
You just need to pass the option `logLevel` to the plugin option or the route
|
||||
option with the
|
||||
[value](https://github.com/pinojs/pino/blob/master/docs/api.md#level-string)
|
||||
that you need.
|
||||
|
||||
Be aware that if you set the `logLevel` at plugin level, also the
|
||||
Be aware that setting `logLevel` at the plugin level also affects
|
||||
[`setNotFoundHandler`](./Server.md#setnotfoundhandler) and
|
||||
[`setErrorHandler`](./Server.md#seterrorhandler) will be affected.
|
||||
[`setErrorHandler`](./Server.md#seterrorhandler).
|
||||
|
||||
```js
|
||||
// server.js
|
||||
@@ -533,22 +520,21 @@ fastify.register(require('./routes/events'), { logLevel: 'debug' })
|
||||
fastify.listen({ port: 3000 })
|
||||
```
|
||||
|
||||
Or you can directly pass it to a route:
|
||||
Or pass it directly to a route:
|
||||
```js
|
||||
fastify.get('/', { logLevel: 'warn' }, (request, reply) => {
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
```
|
||||
*Remember that the custom log level is applied only to the routes, and not to
|
||||
the global Fastify Logger, accessible with `fastify.log`*
|
||||
*Remember that the custom log level applies only to routes, not to the global
|
||||
Fastify Logger, accessible with `fastify.log`.*
|
||||
|
||||
### Custom Log Serializer
|
||||
<a id="custom-log-serializer"></a>
|
||||
|
||||
In some contexts, you may need to log a large object but it could be a waste of
|
||||
resources for some routes. In this case, you can define custom
|
||||
In some contexts, logging a large object may waste resources. Define custom
|
||||
[`serializers`](https://github.com/pinojs/pino/blob/master/docs/api.md#serializers-object)
|
||||
and attach them in the right context!
|
||||
and attach them in the appropriate context.
|
||||
|
||||
```js
|
||||
const fastify = require('fastify')({ logger: true })
|
||||
@@ -567,7 +553,7 @@ fastify.register(require('./routes/events'), {
|
||||
fastify.listen({ port: 3000 })
|
||||
```
|
||||
|
||||
You can inherit serializers by context:
|
||||
Serializers can be inherited by context:
|
||||
|
||||
```js
|
||||
const fastify = Fastify({
|
||||
@@ -579,7 +565,7 @@ const fastify = Fastify({
|
||||
method: req.method,
|
||||
url: req.url,
|
||||
headers: req.headers,
|
||||
hostname: req.hostname,
|
||||
host: req.host,
|
||||
remoteAddress: req.ip,
|
||||
remotePort: req.socket.remotePort
|
||||
}
|
||||
@@ -616,7 +602,7 @@ retrieve it in the handler.
|
||||
const fastify = require('fastify')()
|
||||
|
||||
function handler (req, reply) {
|
||||
reply.send(reply.context.config.output)
|
||||
reply.send(reply.routeOptions.config.output)
|
||||
}
|
||||
|
||||
fastify.get('/en', { config: { output: 'hello world!' } }, handler)
|
||||
@@ -628,31 +614,29 @@ fastify.listen({ port: 3000 })
|
||||
### Constraints
|
||||
<a id="constraints"></a>
|
||||
|
||||
Fastify supports constraining routes to match only certain requests based on
|
||||
some property of the request, like the `Host` header, or any other value via
|
||||
Fastify supports constraining routes to match certain requests based on
|
||||
properties like the `Host` header or any other value via
|
||||
[`find-my-way`](https://github.com/delvedor/find-my-way) constraints.
|
||||
Constraints are specified in the `constraints` property of the route options.
|
||||
Fastify has two built-in constraints ready for use: the `version` constraint and
|
||||
the `host` constraint, and you can add your own custom constraint strategies to
|
||||
inspect other parts of a request to decide if a route should be executed for a
|
||||
request.
|
||||
Fastify has two built-in constraints: `version` and `host`. Custom constraint
|
||||
strategies can be added to inspect other parts of a request to decide if a route
|
||||
should be executed.
|
||||
|
||||
#### Version Constraints
|
||||
|
||||
You can provide a `version` key in the `constraints` option to a route.
|
||||
Versioned routes allow you to declare multiple handlers for the same HTTP route
|
||||
path, which will then be matched according to each request's `Accept-Version`
|
||||
header. The `Accept-Version` header value should follow the
|
||||
[semver](https://semver.org/) specification, and routes should be declared with
|
||||
exact semver versions for matching.
|
||||
Versioned routes allows multiple handlers to be declared for the same HTTP
|
||||
route path, matched according to the request's `Accept-Version` header.
|
||||
The `Accept-Version` header value should follow the
|
||||
[semver](https://semver.org/) specification, and routes should be declared
|
||||
with exact semver versions for matching.
|
||||
|
||||
Fastify will require a request `Accept-Version` header to be set if the route
|
||||
has a version set, and will prefer a versioned route to a non-versioned route
|
||||
for the same path. Advanced version ranges and pre-releases currently are not
|
||||
supported.
|
||||
|
||||
*Be aware that using this feature will cause a degradation of the overall
|
||||
performances of the router.*
|
||||
> **Note:** using this feature can degrade the router’s performance.
|
||||
|
||||
```js
|
||||
fastify.route({
|
||||
@@ -675,20 +659,20 @@ fastify.inject({
|
||||
})
|
||||
```
|
||||
|
||||
> ## ⚠ Security Notice
|
||||
> Remember to set a
|
||||
> ⚠ Warning:
|
||||
> Set a
|
||||
> [`Vary`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary)
|
||||
> header in your responses with the value you are using for defining the
|
||||
> versioning (e.g.: `'Accept-Version'`), to prevent cache poisoning attacks. You
|
||||
> can also configure this as part of your Proxy/CDN.
|
||||
> header in responses with the value used for versioning
|
||||
> (e.g., `'Accept-Version'`) to prevent cache poisoning attacks.
|
||||
> This can also be configured in a Proxy/CDN.
|
||||
>
|
||||
> ```js
|
||||
> const append = require('vary').append
|
||||
> fastify.addHook('onSend', (req, reply, payload, done) => {
|
||||
> if (req.headers['accept-version']) { // or the custom header you are using
|
||||
> if (req.headers['accept-version']) { // or the custom header being used
|
||||
> let value = reply.getHeader('Vary') || ''
|
||||
> const header = Array.isArray(value) ? value.join(', ') : String(value)
|
||||
> if ((value = append(header, 'Accept-Version'))) { // or the custom header you are using
|
||||
> if ((value = append(header, 'Accept-Version'))) { // or the custom header being used
|
||||
> reply.header('Vary', value)
|
||||
> }
|
||||
> }
|
||||
@@ -696,22 +680,20 @@ fastify.inject({
|
||||
> })
|
||||
> ```
|
||||
|
||||
If you declare multiple versions with the same major or minor, Fastify will
|
||||
If multiple versions with the same major or minor are declared, Fastify will
|
||||
always choose the highest compatible with the `Accept-Version` header value.
|
||||
|
||||
If the request will not have the `Accept-Version` header, a 404 error will be
|
||||
returned.
|
||||
If the request lacks an `Accept-Version` header, a 404 error will be returned.
|
||||
|
||||
It is possible to define a custom version matching logic. This can be done
|
||||
through the [`constraints`](./Server.md#constraints) configuration when creating
|
||||
a Fastify server instance.
|
||||
Custom version matching logic can be defined through the
|
||||
[`constraints`](./Server.md#constraints) configuration when creating a Fastify
|
||||
server instance.
|
||||
|
||||
#### Host Constraints
|
||||
|
||||
You can provide a `host` key in the `constraints` route option for to limit that
|
||||
route to only be matched for certain values of the request `Host` header. `host`
|
||||
constraint values can be specified as strings for exact matches or RegExps for
|
||||
arbitrary host matching.
|
||||
Provide a `host` key in the `constraints` route option to limit the route to
|
||||
certain values of the request `Host` header. `host` constraint values can be
|
||||
specified as strings for exact matches or RegExps for arbitrary host matching.
|
||||
|
||||
```js
|
||||
fastify.route({
|
||||
@@ -751,7 +733,7 @@ matching wildcard subdomains (or any other pattern):
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
constraints: { host: /.*\.fastify\.io/ }, // will match any subdomain of fastify.dev
|
||||
constraints: { host: /.*\.fastify\.dev/ }, // will match any subdomain of fastify.dev
|
||||
handler: function (request, reply) {
|
||||
reply.send('hello world from ' + request.headers.host)
|
||||
}
|
||||
@@ -760,10 +742,9 @@ fastify.route({
|
||||
|
||||
#### Asynchronous Custom Constraints
|
||||
|
||||
Custom constraints can be provided and the `constraint` criteria can be
|
||||
fetched from another source such as `database`. The use of asynchronous
|
||||
custom constraints should be a last resort as it impacts router
|
||||
performance.
|
||||
Custom constraints can be provided, and the `constraint` criteria can be
|
||||
fetched from another source such as a database. Use asynchronous custom
|
||||
constraints as a last resort, as they impact router performance.
|
||||
|
||||
```js
|
||||
function databaseOperation(field, done) {
|
||||
@@ -790,18 +771,18 @@ const secret = {
|
||||
}
|
||||
```
|
||||
|
||||
> ## ⚠ Security Notice
|
||||
> When using with asynchronous constraint. It is highly recommend never return error
|
||||
> inside the callback. If the error is not preventable, it is recommended to provide
|
||||
> a custom `frameworkErrors` handler to deal with it. Otherwise, you route selection
|
||||
> may break or expose sensitive information to attackers.
|
||||
>
|
||||
> ⚠ Warning:
|
||||
> When using asynchronous constraints, avoid returning errors inside the
|
||||
> callback. If errors are unavoidable, provide a custom `frameworkErrors`
|
||||
> handler to manage them. Otherwise, route selection may break or expose
|
||||
> sensitive information.
|
||||
>
|
||||
> ```js
|
||||
> const Fastify = require('fastify')
|
||||
>
|
||||
>
|
||||
> const fastify = Fastify({
|
||||
> frameworkErrors: function(err, res, res) {
|
||||
> if(err instanceof Fastify.errorCodes.FST_ERR_ASYNC_CONSTRAINT) {
|
||||
> frameworkErrors: function (err, req, res) {
|
||||
> if (err instanceof Fastify.errorCodes.FST_ERR_ASYNC_CONSTRAINT) {
|
||||
> res.code(400)
|
||||
> return res.send("Invalid header provided")
|
||||
> } else {
|
||||
@@ -810,25 +791,3 @@ const secret = {
|
||||
> }
|
||||
> })
|
||||
> ```
|
||||
|
||||
|
||||
### ⚠ HTTP version check
|
||||
|
||||
Fastify will check the HTTP version of every request, based on configuration
|
||||
options ([http2](./Server.md#http2), [https](./Server.md#https), and
|
||||
[serverFactory](./Server.md#serverfactory)), to determine if it matches one or
|
||||
all of the > following versions: `2.0`, `1.1`, and `1.0`. If Fastify receives a
|
||||
different HTTP version in the request it will return a `505 HTTP Version Not
|
||||
Supported` error.
|
||||
|
||||
| | 2.0 | 1.1 | 1.0 | skip |
|
||||
|:------------------------:|:---:|:---:|:---:|:----:|
|
||||
| http2 | ✓ | | | |
|
||||
| http2 + https | ✓ | | | |
|
||||
| http2 + https.allowHTTP1 | ✓ | ✓ | ✓ | |
|
||||
| https | | ✓ | ✓ | |
|
||||
| http | | ✓ | ✓ | |
|
||||
| serverFactory | | | | ✓ |
|
||||
|
||||
Note: The internal HTTP version check will be removed in the future when Node
|
||||
implements [this feature](https://github.com/nodejs/node/issues/43115).
|
||||
|
||||
809
backend/node_modules/fastify/docs/Reference/Server.md
generated
vendored
809
backend/node_modules/fastify/docs/Reference/Server.md
generated
vendored
File diff suppressed because it is too large
Load Diff
87
backend/node_modules/fastify/docs/Reference/Type-Providers.md
generated
vendored
87
backend/node_modules/fastify/docs/Reference/Type-Providers.md
generated
vendored
@@ -2,18 +2,16 @@
|
||||
|
||||
## Type Providers
|
||||
|
||||
Type Providers are a TypeScript only feature that enables Fastify to statically
|
||||
infer type information directly from inline JSON Schema. They are an alternative
|
||||
to specifying generic arguments on routes; and can greatly reduce the need to
|
||||
keep associated types for each schema defined in your project.
|
||||
Type Providers are a TypeScript feature that enables Fastify to infer type
|
||||
information from inline JSON Schema. They are an alternative to specifying
|
||||
generic arguments on routes and can reduce the need to keep associated types for
|
||||
each schema in a project.
|
||||
|
||||
### Providers
|
||||
|
||||
Type Providers are offered as additional packages you will need to install into
|
||||
your project. Each provider uses a different inference library under the hood;
|
||||
allowing you to select the library most appropriate for your needs. Official Type
|
||||
Provider packages follow a `@fastify/type-provider-{provider-name}` naming
|
||||
convention, and there are several community ones available as well.
|
||||
Official Type Provider packages follow the
|
||||
`@fastify/type-provider-{provider-name}` naming convention.
|
||||
Several community providers are also available.
|
||||
|
||||
The following inference packages are supported:
|
||||
|
||||
@@ -30,78 +28,73 @@ See also the Type Provider wrapper packages for each of the packages respectivel
|
||||
|
||||
### Json Schema to Ts
|
||||
|
||||
The following sets up a `json-schema-to-ts` Type Provider
|
||||
The following sets up a `json-schema-to-ts` Type Provider:
|
||||
|
||||
```bash
|
||||
$ npm i @fastify/type-provider-json-schema-to-ts
|
||||
```
|
||||
|
||||
```typescript
|
||||
import { JsonSchemaToTsProvider } from '@fastify/type-provider-json-schema-to-ts'
|
||||
|
||||
import fastify from 'fastify'
|
||||
import { JsonSchemaToTsProvider } from '@fastify/type-provider-json-schema-to-ts'
|
||||
|
||||
const server = fastify().withTypeProvider<JsonSchemaToTsProvider>()
|
||||
|
||||
server.get('/route', {
|
||||
schema: {
|
||||
querystring: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'number' },
|
||||
bar: { type: 'string' },
|
||||
},
|
||||
required: ['foo', 'bar']
|
||||
}
|
||||
schema: {
|
||||
querystring: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: { type: 'number' },
|
||||
bar: { type: 'string' },
|
||||
},
|
||||
required: ['foo', 'bar']
|
||||
}
|
||||
|
||||
}
|
||||
}, (request, reply) => {
|
||||
|
||||
// type Query = { foo: number, bar: string }
|
||||
|
||||
const { foo, bar } = request.query // type safe!
|
||||
// type Query = { foo: number, bar: string }
|
||||
const { foo, bar } = request.query // type safe!
|
||||
})
|
||||
```
|
||||
|
||||
### TypeBox
|
||||
|
||||
The following sets up a TypeBox Type Provider
|
||||
The following sets up a TypeBox Type Provider:
|
||||
|
||||
```bash
|
||||
$ npm i @fastify/type-provider-typebox
|
||||
```
|
||||
|
||||
```typescript
|
||||
import fastify from 'fastify'
|
||||
import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
|
||||
import { Type } from '@sinclair/typebox'
|
||||
|
||||
import fastify from 'fastify'
|
||||
|
||||
const server = fastify().withTypeProvider<TypeBoxTypeProvider>()
|
||||
|
||||
server.get('/route', {
|
||||
schema: {
|
||||
querystring: Type.Object({
|
||||
foo: Type.Number(),
|
||||
bar: Type.String()
|
||||
})
|
||||
}
|
||||
schema: {
|
||||
querystring: Type.Object({
|
||||
foo: Type.Number(),
|
||||
bar: Type.String()
|
||||
})
|
||||
}
|
||||
}, (request, reply) => {
|
||||
|
||||
// type Query = { foo: number, bar: string }
|
||||
|
||||
const { foo, bar } = request.query // type safe!
|
||||
// type Query = { foo: number, bar: string }
|
||||
const { foo, bar } = request.query // type safe!
|
||||
})
|
||||
```
|
||||
|
||||
See also the [TypeBox
|
||||
documentation](https://github.com/sinclairzx81/typebox#validation) on how to set
|
||||
up AJV to work with TypeBox.
|
||||
See the [TypeBox
|
||||
documentation](https://sinclairzx81.github.io/typebox/#/docs/overview/2_setup)
|
||||
for setting-up AJV to work with TypeBox.
|
||||
|
||||
### Zod
|
||||
|
||||
See [official documentation](https://github.com/turkerdev/fastify-type-provider-zod)
|
||||
for Zod type provider instructions.
|
||||
for Zod Type Provider instructions.
|
||||
|
||||
|
||||
### Scoped Type-Provider
|
||||
@@ -159,9 +152,9 @@ fastify.register(pluginWithJsonSchema)
|
||||
fastify.register(pluginWithTypebox)
|
||||
```
|
||||
|
||||
It's also important to mention that once the types don't propagate globally,
|
||||
_currently_ is not possible to avoid multiple registrations on routes when
|
||||
dealing with several scopes, see below:
|
||||
It is important to note that since the types do not propagate globally, it is
|
||||
currently not possible to avoid multiple registrations on routes when dealing
|
||||
with several scopes, as shown below:
|
||||
|
||||
```ts
|
||||
import Fastify from 'fastify'
|
||||
@@ -183,7 +176,7 @@ function plugin1(fastify: FastifyInstance, _opts, done): void {
|
||||
})
|
||||
}
|
||||
}, (req) => {
|
||||
// it doesn't work! in a new scope needs to call `withTypeProvider` again
|
||||
// In a new scope, call `withTypeProvider` again to ensure it works
|
||||
const { x, y, z } = req.body
|
||||
});
|
||||
done()
|
||||
@@ -210,8 +203,8 @@ function plugin2(fastify: FastifyInstance, _opts, done): void {
|
||||
|
||||
### Type Definition of FastifyInstance + TypeProvider
|
||||
|
||||
When working with modules one has to make use of `FastifyInstance` with Type
|
||||
Provider generics. See the example below:
|
||||
When working with modules, use `FastifyInstance` with Type Provider generics.
|
||||
See the example below:
|
||||
|
||||
```ts
|
||||
// index.ts
|
||||
|
||||
255
backend/node_modules/fastify/docs/Reference/TypeScript.md
generated
vendored
255
backend/node_modules/fastify/docs/Reference/TypeScript.md
generated
vendored
@@ -147,7 +147,7 @@ route-level `request` object.
|
||||
reply.code(200).send('uh-oh');
|
||||
// it even works for wildcards
|
||||
reply.code(404).send({ error: 'Not found' });
|
||||
return `logged in!`
|
||||
return { success: true }
|
||||
})
|
||||
```
|
||||
|
||||
@@ -173,7 +173,7 @@ route-level `request` object.
|
||||
}, async (request, reply) => {
|
||||
const customerHeader = request.headers['h-Custom']
|
||||
// do something with request data
|
||||
return `logged in!`
|
||||
return { success: true }
|
||||
})
|
||||
```
|
||||
7. Build and run and query with the `username` query string option set to
|
||||
@@ -182,7 +182,7 @@ route-level `request` object.
|
||||
admin"}`
|
||||
|
||||
🎉 Good work, now you can define interfaces for each route and have strictly
|
||||
typed request and reply instances. Other parts of the Fastify type system rely
|
||||
typed request and reply instances. Other parts of the Fastify type system rely
|
||||
on generic properties. Make sure to reference the detailed type system
|
||||
documentation below to learn more about what is available.
|
||||
|
||||
@@ -210,24 +210,23 @@ And a `zod` wrapper by a third party called [`fastify-type-provider-zod`](https:
|
||||
They simplify schema validation setup and you can read more about them in [Type
|
||||
Providers](./Type-Providers.md) page.
|
||||
|
||||
Below is how to setup schema validation using _vanilla_ `typebox` and
|
||||
`json-schema-to-ts` packages.
|
||||
Below is how to setup schema validation using the `typebox`,
|
||||
`json-schema-to-typescript`, and `json-schema-to-ts` packages without type
|
||||
providers.
|
||||
|
||||
#### TypeBox
|
||||
|
||||
A useful library for building types and a schema at once is
|
||||
[TypeBox](https://www.npmjs.com/package/@sinclair/typebox) along with
|
||||
[fastify-type-provider-typebox](https://github.com/fastify/fastify-type-provider-typebox).
|
||||
With TypeBox you define your schema within your code and use them
|
||||
directly as types or schemas as you need them.
|
||||
A useful library for building types and a schema at once is [TypeBox](https://www.npmjs.com/package/@sinclair/typebox).
|
||||
With TypeBox you define your schema within your code and use them directly as
|
||||
types or schemas as you need them.
|
||||
|
||||
When you want to use it for validation of some payload in a fastify route you
|
||||
can do it as follows:
|
||||
|
||||
1. Install `typebox` and `fastify-type-provider-typebox` in your project.
|
||||
1. Install `typebox` in your project.
|
||||
|
||||
```bash
|
||||
npm i @sinclair/typebox @fastify/type-provider-typebox
|
||||
npm i @sinclair/typebox
|
||||
```
|
||||
|
||||
2. Define the schema you need with `Type` and create the respective type with
|
||||
@@ -248,10 +247,9 @@ can do it as follows:
|
||||
|
||||
```typescript
|
||||
import Fastify from 'fastify'
|
||||
import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
|
||||
// ...
|
||||
|
||||
const fastify = Fastify().withTypeProvider<TypeBoxTypeProvider>()
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post<{ Body: UserType, Reply: UserType }>(
|
||||
'/',
|
||||
@@ -271,12 +269,12 @@ can do it as follows:
|
||||
)
|
||||
```
|
||||
|
||||
#### Schemas in JSON Files
|
||||
#### json-schema-to-typescript
|
||||
|
||||
In the last example we used interfaces to define the types for the request
|
||||
querystring and headers. Many users will already be using JSON Schemas to define
|
||||
these properties, and luckily there is a way to transform existing JSON Schemas
|
||||
into TypeScript interfaces!
|
||||
In the last example we used Typebox to define the types and schemas for our
|
||||
route. Many users will already be using JSON Schemas to define these properties,
|
||||
and luckily there is a way to transform existing JSON Schemas into TypeScript
|
||||
interfaces!
|
||||
|
||||
1. If you did not complete the 'Getting Started' example, go back and follow
|
||||
steps 1-4 first.
|
||||
@@ -596,7 +594,7 @@ your plugin.
|
||||
}
|
||||
|
||||
module.exports = fp(myPlugin, {
|
||||
fastify: '3.x',
|
||||
fastify: '5.x',
|
||||
name: 'my-plugin' // this is used by fastify-plugin to derive the property name
|
||||
})
|
||||
```
|
||||
@@ -634,7 +632,7 @@ newer, automatically adds `.default` property and a named export to the exported
|
||||
plugin. Be sure to `export default` and `export const myPlugin` in your typings
|
||||
to provide the best developer experience. For a complete example you can check
|
||||
out
|
||||
[@fastify/swagger](https://github.com/fastify/fastify-swagger/blob/master/index.d.ts).
|
||||
[@fastify/swagger](https://github.com/fastify/fastify-swagger/blob/main/index.d.ts).
|
||||
|
||||
With those files completed, the plugin is now ready to be consumed by any
|
||||
TypeScript project!
|
||||
@@ -689,6 +687,143 @@ Or even explicit config on tsconfig
|
||||
}
|
||||
```
|
||||
|
||||
#### `getDecorator<T>`
|
||||
|
||||
Fastify's `getDecorator<T>` method retrieves decorators with enhanced type safety.
|
||||
|
||||
The `getDecorator<T>` method supports generic type parameters for enhanced type
|
||||
safety:
|
||||
|
||||
```typescript
|
||||
// Type-safe decorator retrieval
|
||||
const usersRepository = fastify.getDecorator<IUsersRepository>('usersRepository')
|
||||
const session = request.getDecorator<ISession>('session')
|
||||
const sendSuccess = reply.getDecorator<SendSuccessFn>('sendSuccess')
|
||||
```
|
||||
|
||||
**Alternative to Module Augmentation**
|
||||
|
||||
Decorators are typically typed via module augmentation:
|
||||
|
||||
```typescript
|
||||
declare module 'fastify' {
|
||||
interface FastifyInstance {
|
||||
usersRepository: IUsersRepository
|
||||
}
|
||||
interface FastifyRequest {
|
||||
session: ISession
|
||||
}
|
||||
interface FastifyReply {
|
||||
sendSuccess: SendSuccessFn
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This approach modifies the Fastify instance globally, which may lead to conflicts
|
||||
and inconsistent behavior in multi-server setups or with plugin encapsulation.
|
||||
|
||||
Using `getDecorator<T>` allows limiting types scope:
|
||||
|
||||
```typescript
|
||||
serverOne.register(async function (fastify) {
|
||||
const usersRepository = fastify.getDecorator<PostgreUsersRepository>(
|
||||
'usersRepository'
|
||||
)
|
||||
|
||||
fastify.decorateRequest('session', null)
|
||||
fastify.addHook('onRequest', async (req, reply) => {
|
||||
req.setDecorator('session', { user: 'Jean' })
|
||||
})
|
||||
|
||||
fastify.get('/me', (request, reply) => {
|
||||
const session = request.getDecorator<ISession>('session')
|
||||
reply.send(session)
|
||||
})
|
||||
})
|
||||
|
||||
serverTwo.register(async function (fastify) {
|
||||
const usersRepository = fastify.getDecorator<SqlLiteUsersRepository>(
|
||||
'usersRepository'
|
||||
)
|
||||
|
||||
fastify.decorateReply('sendSuccess', function (data) {
|
||||
return this.send({ success: true })
|
||||
})
|
||||
|
||||
fastify.get('/success', async (request, reply) => {
|
||||
const sendSuccess = reply.getDecorator<SendSuccessFn>('sendSuccess')
|
||||
await sendSuccess()
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
**Bound Functions Inference**
|
||||
|
||||
To save time, it is common to infer function types instead of writing them manually:
|
||||
|
||||
```typescript
|
||||
function sendSuccess (this: FastifyReply) {
|
||||
return this.send({ success: true })
|
||||
}
|
||||
|
||||
export type SendSuccess = typeof sendSuccess
|
||||
```
|
||||
|
||||
However, `getDecorator` returns functions with the `this` context already **bound**,
|
||||
meaning the `this` parameter disappears from the function signature.
|
||||
|
||||
To correctly type it, use the `OmitThisParameter` utility:
|
||||
|
||||
```typescript
|
||||
function sendSuccess (this: FastifyReply) {
|
||||
return this.send({ success: true })
|
||||
}
|
||||
|
||||
type BoundSendSuccess = OmitThisParameter<typeof sendSuccess>
|
||||
|
||||
fastify.decorateReply('sendSuccess', sendSuccess)
|
||||
fastify.get('/success', async (request, reply) => {
|
||||
const sendSuccess = reply.getDecorator<BoundSendSuccess>('sendSuccess')
|
||||
await sendSuccess()
|
||||
})
|
||||
```
|
||||
|
||||
#### `setDecorator<T>`
|
||||
|
||||
Fastify's `setDecorator<T>` method provides enhanced type safety for updating request
|
||||
decorators.
|
||||
|
||||
The `setDecorator<T>` method provides enhanced type safety for updating request
|
||||
decorators:
|
||||
|
||||
```typescript
|
||||
fastify.decorateRequest('user', '')
|
||||
fastify.addHook('preHandler', async (req, reply) => {
|
||||
// Type-safe decorator setting
|
||||
req.setDecorator<string>('user', 'Bob Dylan')
|
||||
})
|
||||
```
|
||||
|
||||
**Type Safety Benefits**
|
||||
|
||||
If the `FastifyRequest` interface does not declare the decorator, type assertions
|
||||
are typically needed:
|
||||
|
||||
```typescript
|
||||
fastify.addHook('preHandler', async (req, reply) => {
|
||||
(req as typeof req & { user: string }).user = 'Bob Dylan'
|
||||
})
|
||||
```
|
||||
|
||||
The `setDecorator<T>` method eliminates the need for explicit type assertions
|
||||
while providing type safety:
|
||||
|
||||
```typescript
|
||||
fastify.addHook('preHandler', async (req, reply) => {
|
||||
req.setDecorator<string>('user', 'Bob Dylan')
|
||||
})
|
||||
```
|
||||
|
||||
## Code Completion In Vanilla JavaScript
|
||||
|
||||
Vanilla JavaScript can use the published types to provide code completion (e.g.
|
||||
@@ -831,7 +966,7 @@ Constraints: `string | Buffer`
|
||||
|
||||
#### Fastify
|
||||
|
||||
##### fastify<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [Logger][LoggerGeneric]>(opts?: [FastifyServerOptions][FastifyServerOptions]): [FastifyInstance][FastifyInstance]
|
||||
##### fastify< [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [Logger][LoggerGeneric]>(opts?: [FastifyServerOptions][FastifyServerOptions]): [FastifyInstance][FastifyInstance]
|
||||
[src](https://github.com/fastify/fastify/blob/main/fastify.d.ts#L19)
|
||||
|
||||
The main Fastify API method. By default creates an HTTP server. Utilizing
|
||||
@@ -858,11 +993,11 @@ a more detailed http server walkthrough.
|
||||
|
||||
1. Create the following imports from `@types/node` and `fastify`
|
||||
```typescript
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import fastify from 'fastify'
|
||||
```
|
||||
2. Perform the following steps before setting up a Fastify HTTPS server
|
||||
2. Perform the following steps before setting up a Fastify HTTPS server
|
||||
to create the `key.pem` and `cert.pem` files:
|
||||
```sh
|
||||
openssl genrsa -out key.pem
|
||||
@@ -920,7 +1055,7 @@ specified at server instantiation, the custom type becomes available on all
|
||||
further instances of the custom type.
|
||||
```typescript
|
||||
import fastify from 'fastify'
|
||||
import http from 'http'
|
||||
import http from 'node:http'
|
||||
|
||||
interface customRequest extends http.IncomingMessage {
|
||||
mySpecialProp: string
|
||||
@@ -986,7 +1121,7 @@ Type alias for `http.Server`
|
||||
|
||||
---
|
||||
|
||||
##### fastify.FastifyServerOptions<[RawServer][RawServerGeneric], [Logger][LoggerGeneric]>
|
||||
##### fastify.FastifyServerOptions< [RawServer][RawServerGeneric], [Logger][LoggerGeneric]>
|
||||
|
||||
[src](https://github.com/fastify/fastify/blob/main/fastify.d.ts#L29)
|
||||
|
||||
@@ -997,7 +1132,7 @@ generic parameters are passed down through that method.
|
||||
See the main [fastify][Fastify] method type definition section for examples on
|
||||
instantiating a Fastify server with TypeScript.
|
||||
|
||||
##### fastify.FastifyInstance<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RequestGeneric][FastifyRequestGenericInterface], [Logger][LoggerGeneric]>
|
||||
##### fastify.FastifyInstance< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RequestGeneric][FastifyRequestGenericInterface], [Logger][LoggerGeneric]>
|
||||
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/instance.d.ts#L16)
|
||||
|
||||
@@ -1020,7 +1155,7 @@ details on this interface.
|
||||
|
||||
#### Request
|
||||
|
||||
##### fastify.FastifyRequest<[RequestGeneric][FastifyRequestGenericInterface], [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric]>
|
||||
##### fastify.FastifyRequest< [RequestGeneric][FastifyRequestGenericInterface], [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric]>
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/request.d.ts#L15)
|
||||
|
||||
This interface contains properties of Fastify request object. The properties
|
||||
@@ -1108,8 +1243,8 @@ returns `http.IncomingMessage`, otherwise, it returns
|
||||
`http2.Http2ServerRequest`.
|
||||
|
||||
```typescript
|
||||
import http from 'http'
|
||||
import http2 from 'http2'
|
||||
import http from 'node:http'
|
||||
import http2 from 'node:http2'
|
||||
import { RawRequestDefaultExpression } from 'fastify'
|
||||
|
||||
RawRequestDefaultExpression<http.Server> // -> http.IncomingMessage
|
||||
@@ -1120,7 +1255,7 @@ RawRequestDefaultExpression<http2.Http2Server> // -> http2.Http2ServerRequest
|
||||
|
||||
#### Reply
|
||||
|
||||
##### fastify.FastifyReply<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>
|
||||
##### fastify.FastifyReply<[RequestGeneric][FastifyRequestGenericInterface], [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [ContextConfig][ContextConfigGeneric]>
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/reply.d.ts#L32)
|
||||
|
||||
This interface contains the custom properties that Fastify adds to the standard
|
||||
@@ -1156,7 +1291,7 @@ declare module 'fastify' {
|
||||
}
|
||||
```
|
||||
|
||||
##### fastify.RawReplyDefaultExpression<[RawServer][RawServerGeneric]>
|
||||
##### fastify.RawReplyDefaultExpression< [RawServer][RawServerGeneric]>
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/utils.d.ts#L27)
|
||||
|
||||
Dependent on `@types/node` modules `http`, `https`, `http2`
|
||||
@@ -1168,8 +1303,8 @@ returns `http.ServerResponse`, otherwise, it returns
|
||||
`http2.Http2ServerResponse`.
|
||||
|
||||
```typescript
|
||||
import http from 'http'
|
||||
import http2 from 'http2'
|
||||
import http from 'node:http'
|
||||
import http2 from 'node:http2'
|
||||
import { RawReplyDefaultExpression } from 'fastify'
|
||||
|
||||
RawReplyDefaultExpression<http.Server> // -> http.ServerResponse
|
||||
@@ -1188,19 +1323,19 @@ When creating plugins for Fastify, it is recommended to use the `fastify-plugin`
|
||||
module. Additionally, there is a guide to creating plugins with TypeScript and
|
||||
Fastify available in the Learn by Example, [Plugins](#plugins) section.
|
||||
|
||||
##### fastify.FastifyPluginCallback<[Options][FastifyPluginOptions]>
|
||||
##### fastify.FastifyPluginCallback< [Options][FastifyPluginOptions]>
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/plugin.d.ts#L9)
|
||||
|
||||
Interface method definition used within the
|
||||
[`fastify.register()`][FastifyRegister] method.
|
||||
|
||||
##### fastify.FastifyPluginAsync<[Options][FastifyPluginOptions]>
|
||||
##### fastify.FastifyPluginAsync< [Options][FastifyPluginOptions]>
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/plugin.d.ts#L20)
|
||||
|
||||
Interface method definition used within the
|
||||
[`fastify.register()`][FastifyRegister] method.
|
||||
|
||||
##### fastify.FastifyPlugin<[Options][FastifyPluginOptions]>
|
||||
##### fastify.FastifyPlugin< [Options][FastifyPluginOptions]>
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/plugin.d.ts#L29)
|
||||
|
||||
Interface method definition used within the
|
||||
@@ -1269,7 +1404,7 @@ a function that returns the previously described intersection.
|
||||
Check out the [Specifying Logger Types](#example-5-specifying-logger-types)
|
||||
example for more details on specifying a custom logger.
|
||||
|
||||
##### fastify.FastifyLoggerOptions<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric]>
|
||||
##### fastify.FastifyLoggerOptions< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric]>
|
||||
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/logger.d.ts#L17)
|
||||
|
||||
@@ -1332,7 +1467,7 @@ One of the core principles in Fastify is its routing capabilities. Most of the
|
||||
types defined in this section are used under-the-hood by the Fastify instance
|
||||
`.route` and `.get/.post/.etc` methods.
|
||||
|
||||
##### fastify.RouteHandlerMethod<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>
|
||||
##### fastify.RouteHandlerMethod< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>
|
||||
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/route.d.ts#L105)
|
||||
|
||||
@@ -1342,7 +1477,7 @@ The generics parameters are passed through to these arguments. The method
|
||||
returns either `void` or `Promise<any>` for synchronous and asynchronous
|
||||
handlers respectively.
|
||||
|
||||
##### fastify.RouteOptions<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>
|
||||
##### fastify.RouteOptions< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>
|
||||
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/route.d.ts#L78)
|
||||
|
||||
@@ -1354,14 +1489,14 @@ required properties:
|
||||
3. `handler` the route handler method, see [RouteHandlerMethod][] for more
|
||||
details
|
||||
|
||||
##### fastify.RouteShorthandMethod<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric]>
|
||||
##### fastify.RouteShorthandMethod< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric]>
|
||||
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/route.d.ts#12)
|
||||
|
||||
An overloaded function interface for three kinds of shorthand route methods to
|
||||
be used in conjunction with the `.get/.post/.etc` methods.
|
||||
|
||||
##### fastify.RouteShorthandOptions<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>
|
||||
##### fastify.RouteShorthandOptions< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>
|
||||
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/route.d.ts#55)
|
||||
|
||||
@@ -1369,7 +1504,7 @@ An interface that covers all of the base options for a route. Each property on
|
||||
this interface is optional, and it serves as the base for the RouteOptions and
|
||||
RouteShorthandOptionsWithHandler interfaces.
|
||||
|
||||
##### fastify.RouteShorthandOptionsWithHandler<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>
|
||||
##### fastify.RouteShorthandOptionsWithHandler< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>
|
||||
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/route.d.ts#93)
|
||||
|
||||
@@ -1384,21 +1519,21 @@ interface `handler` which is of type RouteHandlerMethod
|
||||
|
||||
A generic type that is either a `string` or `Buffer`
|
||||
|
||||
##### fastify.FastifyBodyParser<[RawBody][RawBodyGeneric], [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric]>
|
||||
##### fastify.FastifyBodyParser< [RawBody][RawBodyGeneric], [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric]>
|
||||
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/content-type-parser.d.ts#L7)
|
||||
|
||||
A function type definition for specifying a body parser method. Use the
|
||||
`RawBody` generic to specify the type of the body being parsed.
|
||||
|
||||
##### fastify.FastifyContentTypeParser<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric]>
|
||||
##### fastify.FastifyContentTypeParser< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric]>
|
||||
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/content-type-parser.d.ts#L17)
|
||||
|
||||
A function type definition for specifying a body parser method. Content is typed
|
||||
via the `RawRequest` generic.
|
||||
|
||||
##### fastify.AddContentTypeParser<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric]>
|
||||
##### fastify.AddContentTypeParser< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric]>
|
||||
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/content-type-parser.d.ts#L46)
|
||||
|
||||
@@ -1440,7 +1575,7 @@ This interface is passed to instance of FastifyError.
|
||||
|
||||
#### Hooks
|
||||
|
||||
##### fastify.onRequestHookHandler<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>(request: [FastifyRequest][FastifyRequest], reply: [FastifyReply][FastifyReply], done: (err?: [FastifyError][FastifyError]) => void): Promise\<unknown\> | void
|
||||
##### fastify.onRequestHookHandler< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>(request: [FastifyRequest][FastifyRequest], reply: [FastifyReply][FastifyReply], done: (err?: [FastifyError][FastifyError]) => void): Promise\<unknown\> | void
|
||||
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L17)
|
||||
|
||||
@@ -1450,7 +1585,7 @@ no previous hook, the next hook will be `preParsing`.
|
||||
Notice: in the `onRequest` hook, request.body will always be null, because the
|
||||
body parsing happens before the `preHandler` hook.
|
||||
|
||||
##### fastify.preParsingHookHandler<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>(request: [FastifyRequest][FastifyRequest], reply: [FastifyReply][FastifyReply], done: (err?: [FastifyError][FastifyError]) => void): Promise\<unknown\> | void
|
||||
##### fastify.preParsingHookHandler< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>(request: [FastifyRequest][FastifyRequest], reply: [FastifyReply][FastifyReply], done: (err?: [FastifyError][FastifyError]) => void): Promise\<unknown\> | void
|
||||
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L35)
|
||||
|
||||
@@ -1465,21 +1600,21 @@ stream. This property is used to correctly match the request payload with the
|
||||
`Content-Length` header value. Ideally, this property should be updated on each
|
||||
received chunk.
|
||||
|
||||
##### fastify.preValidationHookHandler<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>(request: [FastifyRequest][FastifyRequest], reply: [FastifyReply][FastifyReply], done: (err?: [FastifyError][FastifyError]) => void): Promise\<unknown\> | void
|
||||
##### fastify.preValidationHookHandler< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>(request: [FastifyRequest][FastifyRequest], reply: [FastifyReply][FastifyReply], done: (err?: [FastifyError][FastifyError]) => void): Promise\<unknown\> | void
|
||||
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L53)
|
||||
|
||||
`preValidation` is the third hook to be executed in the request lifecycle. The
|
||||
previous hook was `preParsing`, the next hook will be `preHandler`.
|
||||
|
||||
##### fastify.preHandlerHookHandler<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>(request: [FastifyRequest][FastifyRequest], reply: [FastifyReply][FastifyReply], done: (err?: [FastifyError][FastifyError]) => void): Promise\<unknown\> | void
|
||||
##### fastify.preHandlerHookHandler< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>(request: [FastifyRequest][FastifyRequest], reply: [FastifyReply][FastifyReply], done: (err?: [FastifyError][FastifyError]) => void): Promise\<unknown\> | void
|
||||
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L70)
|
||||
|
||||
`preHandler` is the fourth hook to be executed in the request lifecycle. The
|
||||
previous hook was `preValidation`, the next hook will be `preSerialization`.
|
||||
|
||||
##### fastify.preSerializationHookHandler<PreSerializationPayload, [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>(request: [FastifyRequest][FastifyRequest], reply: [FastifyReply][FastifyReply], payload: PreSerializationPayload, done: (err: [FastifyError][FastifyError] | null, res?: unknown) => void): Promise\<unknown\> | void
|
||||
##### fastify.preSerializationHookHandler< PreSerializationPayload, [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>(request: [FastifyRequest][FastifyRequest], reply: [FastifyReply][FastifyReply], payload: PreSerializationPayload, done: (err: [FastifyError][FastifyError] | null, res?: unknown) => void): Promise\<unknown\> | void
|
||||
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L94)
|
||||
|
||||
@@ -1489,7 +1624,7 @@ The previous hook was `preHandler`, the next hook will be `onSend`.
|
||||
Note: the hook is NOT called if the payload is a string, a Buffer, a stream or
|
||||
null.
|
||||
|
||||
##### fastify.onSendHookHandler<OnSendPayload, [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>(request: [FastifyRequest][FastifyRequest], reply: [FastifyReply][FastifyReply], payload: OnSendPayload, done: (err: [FastifyError][FastifyError] | null, res?: unknown) => void): Promise\<unknown\> | void
|
||||
##### fastify.onSendHookHandler< OnSendPayload, [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>(request: [FastifyRequest][FastifyRequest], reply: [FastifyReply][FastifyReply], payload: OnSendPayload, done: (err: [FastifyError][FastifyError] | null, res?: unknown) => void): Promise\<unknown\> | void
|
||||
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L114)
|
||||
|
||||
@@ -1500,7 +1635,7 @@ next hook will be `onResponse`.
|
||||
Note: If you change the payload, you may only change it to a string, a Buffer, a
|
||||
stream, or null.
|
||||
|
||||
##### fastify.onResponseHookHandler<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>(request: [FastifyRequest][FastifyRequest], reply: [FastifyReply][FastifyReply], done: (err?: [FastifyError][FastifyError]) => void): Promise\<unknown\> | void
|
||||
##### fastify.onResponseHookHandler< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>(request: [FastifyRequest][FastifyRequest], reply: [FastifyReply][FastifyReply], done: (err?: [FastifyError][FastifyError]) => void): Promise\<unknown\> | void
|
||||
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L134)
|
||||
|
||||
@@ -1511,7 +1646,7 @@ The onResponse hook is executed when a response has been sent, so you will not
|
||||
be able to send more data to the client. It can however be useful for sending
|
||||
data to external services, for example to gather statistics.
|
||||
|
||||
##### fastify.onErrorHookHandler<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>(request: [FastifyRequest][FastifyRequest], reply: [FastifyReply][FastifyReply], error: [FastifyError][FastifyError], done: () => void): Promise\<unknown\> | void
|
||||
##### fastify.onErrorHookHandler< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>(request: [FastifyRequest][FastifyRequest], reply: [FastifyReply][FastifyReply], error: [FastifyError][FastifyError], done: () => void): Promise\<unknown\> | void
|
||||
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L154)
|
||||
|
||||
@@ -1521,14 +1656,12 @@ specific header in case of error.
|
||||
It is not intended for changing the error, and calling reply.send will throw an
|
||||
exception.
|
||||
|
||||
This hook will be executed only after the customErrorHandler has been executed,
|
||||
and only if the customErrorHandler sends an error back to the user (Note that
|
||||
the default customErrorHandler always sends the error back to the user).
|
||||
This hook will be executed before the customErrorHandler.
|
||||
|
||||
Notice: unlike the other hooks, pass an error to the done function is not
|
||||
supported.
|
||||
|
||||
##### fastify.onRouteHookHandler<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>(opts: [RouteOptions][RouteOptions] & { path: string; prefix: string }): Promise\<unknown\> | void
|
||||
##### fastify.onRouteHookHandler< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>(opts: [RouteOptions][RouteOptions] & \{ path: string; prefix: string }): Promise\<unknown\> | void
|
||||
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L174)
|
||||
|
||||
@@ -1536,7 +1669,7 @@ Triggered when a new route is registered. Listeners are passed a routeOptions
|
||||
object as the sole parameter. The interface is synchronous, and, as such, the
|
||||
listener does not get passed a callback
|
||||
|
||||
##### fastify.onRegisterHookHandler<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [Logger][LoggerGeneric]>(instance: [FastifyInstance][FastifyInstance], done: (err?: [FastifyError][FastifyError]) => void): Promise\<unknown\> | void
|
||||
##### fastify.onRegisterHookHandler< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [Logger][LoggerGeneric]>(instance: [FastifyInstance][FastifyInstance], done: (err?: [FastifyError][FastifyError]) => void): Promise\<unknown\> | void
|
||||
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L191)
|
||||
|
||||
@@ -1548,7 +1681,7 @@ plugin context is formed, and you want to operate in that specific context.
|
||||
|
||||
Note: This hook will not be called if a plugin is wrapped inside fastify-plugin.
|
||||
|
||||
##### fastify.onCloseHookHandler<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [Logger][LoggerGeneric]>(instance: [FastifyInstance][FastifyInstance], done: (err?: [FastifyError][FastifyError]) => void): Promise\<unknown\> | void
|
||||
##### fastify.onCloseHookHandler< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [Logger][LoggerGeneric]>(instance: [FastifyInstance][FastifyInstance], done: (err?: [FastifyError][FastifyError]) => void): Promise\<unknown\> | void
|
||||
|
||||
[src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L206)
|
||||
|
||||
|
||||
418
backend/node_modules/fastify/docs/Reference/Validation-and-Serialization.md
generated
vendored
418
backend/node_modules/fastify/docs/Reference/Validation-and-Serialization.md
generated
vendored
@@ -1,67 +1,63 @@
|
||||
<h1 align="center">Fastify</h1>
|
||||
|
||||
## Validation and Serialization
|
||||
Fastify uses a schema-based approach, and even if it is not mandatory we
|
||||
recommend using [JSON Schema](https://json-schema.org/) to validate your routes
|
||||
and serialize your outputs. Internally, Fastify compiles the schema into a
|
||||
highly performant function.
|
||||
Fastify uses a schema-based approach. We recommend using
|
||||
[JSON Schema](https://json-schema.org/) to validate routes and serialize outputs.
|
||||
Fastify compiles the schema into a highly performant function.
|
||||
|
||||
Validation will only be attempted if the content type is `application-json`, as
|
||||
described in the documentation for the [content type
|
||||
parser](./ContentTypeParser.md).
|
||||
Validation is only attempted if the content type is `application/json`.
|
||||
|
||||
All the examples in this section are using the [JSON Schema Draft
|
||||
7](https://json-schema.org/specification-links.html#draft-7) specification.
|
||||
All examples use the
|
||||
[JSON Schema Draft 7](https://json-schema.org/specification-links.html#draft-7)
|
||||
specification.
|
||||
|
||||
> ## ⚠ Security Notice
|
||||
> Treat the schema definition as application code. Validation and serialization
|
||||
> features dynamically evaluate code with `new Function()`, which is not safe to
|
||||
> use with user-provided schemas. See [Ajv](https://npm.im/ajv) and
|
||||
> [fast-json-stringify](https://npm.im/fast-json-stringify) for more details.
|
||||
> ⚠ Warning:
|
||||
> Treat schema definitions as application code. Validation and serialization
|
||||
> features use `new Function()`, which is unsafe with user-provided schemas. See
|
||||
> [Ajv](https://npm.im/ajv) and
|
||||
> [fast-json-stringify](https://npm.im/fast-json-stringify) for details.
|
||||
>
|
||||
> Regardless the [`$async` Ajv
|
||||
> feature](https://ajv.js.org/guide/async-validation.html) is supported
|
||||
> by Fastify, it should not be used as
|
||||
> part of the first validation strategy. This option is used to access Databases
|
||||
> and reading them during the validation process may lead to Denial of Service
|
||||
> Attacks to your application. If you need to run `async` tasks, use [Fastify's
|
||||
> hooks](./Hooks.md) instead after validation completes, such as `preHandler`.
|
||||
|
||||
> Whilst Fastify supports the
|
||||
> [`$async` Ajv feature](https://ajv.js.org/guide/async-validation.html),
|
||||
> it should not be used for initial validation. Accessing databases during
|
||||
> validation may lead to Denial of Service attacks. Use
|
||||
> [Fastify's hooks](./Hooks.md) like `preHandler` for `async` tasks after validation.
|
||||
>
|
||||
> When using custom validators with async `preValidation` hooks,
|
||||
> validators **must return** `{error}` objects instead of throwing errors.
|
||||
> Throwing errors from custom validators will cause unhandled promise rejections
|
||||
> that crash the application when combined with async hooks. See the
|
||||
> [custom validator examples](#using-other-validation-libraries) below for the
|
||||
> correct pattern.
|
||||
|
||||
### Core concepts
|
||||
The validation and the serialization tasks are processed by two different, and
|
||||
customizable, actors:
|
||||
- [Ajv v8](https://www.npmjs.com/package/ajv) for the validation of a request
|
||||
Validation and serialization are handled by two customizable dependencies:
|
||||
- [Ajv v8](https://www.npmjs.com/package/ajv) for request validation
|
||||
- [fast-json-stringify](https://www.npmjs.com/package/fast-json-stringify) for
|
||||
the serialization of a response's body
|
||||
response body serialization
|
||||
|
||||
These two separate entities share only the JSON schemas added to Fastify's
|
||||
instance through `.addSchema(schema)`.
|
||||
These dependencies share only the JSON schemas added to Fastify's instance via
|
||||
`.addSchema(schema)`.
|
||||
|
||||
#### Adding a shared schema
|
||||
<a id="shared-schema"></a>
|
||||
|
||||
Thanks to the `addSchema` API, you can add multiple schemas to the Fastify
|
||||
instance and then reuse them in multiple parts of your application. As usual,
|
||||
this API is encapsulated.
|
||||
The `addSchema` API allows adding multiple schemas to the Fastify instance for
|
||||
reuse throughout the application. This API is encapsulated.
|
||||
|
||||
The shared schemas can be reused through the JSON Schema
|
||||
Shared schemas can be reused with the JSON Schema
|
||||
[**`$ref`**](https://tools.ietf.org/html/draft-handrews-json-schema-01#section-8)
|
||||
keyword. Here is an overview of _how_ references work:
|
||||
keyword. Here is an overview of how references work:
|
||||
|
||||
+ `myField: { $ref: '#foo'}` will search for field with `$id: '#foo'` inside the
|
||||
+ `myField: { $ref: '#foo' }` searches for `$id: '#foo'` in the current schema
|
||||
+ `myField: { $ref: '#/definitions/foo' }` searches for `definitions.foo` in the
|
||||
current schema
|
||||
+ `myField: { $ref: '#/definitions/foo'}` will search for field
|
||||
`definitions.foo` inside the current schema
|
||||
+ `myField: { $ref: 'http://url.com/sh.json#'}` will search for a shared schema
|
||||
added with `$id: 'http://url.com/sh.json'`
|
||||
+ `myField: { $ref: 'http://url.com/sh.json#/definitions/foo'}` will search for
|
||||
a shared schema added with `$id: 'http://url.com/sh.json'` and will use the
|
||||
field `definitions.foo`
|
||||
+ `myField: { $ref: 'http://url.com/sh.json#foo'}` will search for a shared
|
||||
schema added with `$id: 'http://url.com/sh.json'` and it will look inside of
|
||||
it for object with `$id: '#foo'`
|
||||
|
||||
+ `myField: { $ref: 'http://url.com/sh.json#' }` searches for a shared schema
|
||||
with `$id: 'http://url.com/sh.json'`
|
||||
+ `myField: { $ref: 'http://url.com/sh.json#/definitions/foo' }` searches for a
|
||||
shared schema with `$id: 'http://url.com/sh.json'` and uses `definitions.foo`
|
||||
+ `myField: { $ref: 'http://url.com/sh.json#foo' }` searches for a shared schema
|
||||
with `$id: 'http://url.com/sh.json'` and looks for `$id: '#foo'` within it
|
||||
|
||||
**Simple usage:**
|
||||
|
||||
@@ -108,9 +104,9 @@ fastify.post('/', {
|
||||
#### Retrieving the shared schemas
|
||||
<a id="get-shared-schema"></a>
|
||||
|
||||
If the validator and the serializer are customized, the `.addSchema` method will
|
||||
not be useful since the actors are no longer controlled by Fastify. To access
|
||||
the schemas added to the Fastify instance, you can simply use `.getSchemas()`:
|
||||
If the validator and serializer are customized, `.addSchema` is not useful since
|
||||
Fastify no longer controls them. To access schemas added to the Fastify instance,
|
||||
use `.getSchemas()`:
|
||||
|
||||
```js
|
||||
fastify.addSchema({
|
||||
@@ -125,8 +121,8 @@ const mySchemas = fastify.getSchemas()
|
||||
const mySchema = fastify.getSchema('schemaId')
|
||||
```
|
||||
|
||||
As usual, the function `getSchemas` is encapsulated and returns the shared
|
||||
schemas available in the selected scope:
|
||||
The `getSchemas` function is encapsulated and returns shared schemas available
|
||||
in the selected scope:
|
||||
|
||||
```js
|
||||
fastify.addSchema({ $id: 'one', my: 'hello' })
|
||||
@@ -150,25 +146,22 @@ fastify.register((instance, opts, done) => {
|
||||
|
||||
|
||||
### Validation
|
||||
The route validation internally relies upon [Ajv
|
||||
v8](https://www.npmjs.com/package/ajv) which is a high-performance JSON Schema
|
||||
validator. Validating the input is very easy: just add the fields that you need
|
||||
inside the route schema, and you are done!
|
||||
Route validation relies on [Ajv v8](https://www.npmjs.com/package/ajv), a
|
||||
high-performance JSON Schema validator. To validate input, add the required
|
||||
fields to the route schema.
|
||||
|
||||
The supported validations are:
|
||||
- `body`: validates the body of the request if it is a POST, PUT, or PATCH
|
||||
method.
|
||||
Supported validations include:
|
||||
- `body`: validates the request body for POST, PUT, or PATCH methods.
|
||||
- `querystring` or `query`: validates the query string.
|
||||
- `params`: validates the route params.
|
||||
- `params`: validates the route parameters.
|
||||
- `headers`: validates the request headers.
|
||||
|
||||
All the validations can be a complete JSON Schema object (with a `type` property
|
||||
of `'object'` and a `'properties'` object containing parameters) or a simpler
|
||||
variation in which the `type` and `properties` attributes are forgone and the
|
||||
parameters are listed at the top level (see the example below).
|
||||
Validations can be a complete JSON Schema object with a `type` of `'object'` and
|
||||
a `'properties'` object containing parameters, or a simpler variation listing
|
||||
parameters at the top level.
|
||||
|
||||
> ℹ If you need to use the latest version of Ajv (v8) you should read how to do
|
||||
> it in the [`schemaController`](./Server.md#schema-controller) section.
|
||||
> ℹ For using the latest Ajv (v8), refer to the
|
||||
> [`schemaController`](./Server.md#schema-controller) section.
|
||||
|
||||
Example:
|
||||
```js
|
||||
@@ -257,9 +250,9 @@ fastify.post('/the/url', {
|
||||
}, handler)
|
||||
```
|
||||
|
||||
*Note that Ajv will try to [coerce](https://ajv.js.org/coercion.html) the values
|
||||
to the types specified in your schema `type` keywords, both to pass the
|
||||
validation and to use the correctly typed data afterwards.*
|
||||
Note that Ajv will try to [coerce](https://ajv.js.org/coercion.html) values to
|
||||
the types specified in the schema `type` keywords, both to pass validation and
|
||||
to use the correctly typed data afterwards.
|
||||
|
||||
The Ajv default configuration in Fastify supports coercing array parameters in
|
||||
`querystring`. Example:
|
||||
@@ -294,11 +287,11 @@ curl -X GET "http://localhost:3000/?ids=1
|
||||
{"params":{"ids":["1"]}}
|
||||
```
|
||||
|
||||
You can also specify a custom schema validator for each parameter type (body,
|
||||
A custom schema validator can be specified for each parameter type (body,
|
||||
querystring, params, headers).
|
||||
|
||||
For example, the following code disable type coercion only for the `body`
|
||||
parameters, changing the ajv default options:
|
||||
For example, the following code disables type coercion only for the `body`
|
||||
parameters, changing the Ajv default options:
|
||||
|
||||
```js
|
||||
const schemaCompilers = {
|
||||
@@ -336,16 +329,15 @@ server.setValidatorCompiler(req => {
|
||||
})
|
||||
```
|
||||
|
||||
For further information see [here](https://ajv.js.org/coercion.html)
|
||||
For more information, see [Ajv Coercion](https://ajv.js.org/coercion.html).
|
||||
|
||||
#### Ajv Plugins
|
||||
<a id="ajv-plugins"></a>
|
||||
|
||||
You can provide a list of plugins you want to use with the default `ajv`
|
||||
instance. Note that the plugin must be **compatible with the Ajv version shipped
|
||||
within Fastify**.
|
||||
A list of plugins can be provided for use with the default `ajv` instance.
|
||||
Ensure the plugin is **compatible with the Ajv version shipped within Fastify**.
|
||||
|
||||
> Refer to [`ajv options`](./Server.md#ajv) to check plugins format
|
||||
> Refer to [`ajv options`](./Server.md#ajv) to check plugins format.
|
||||
|
||||
```js
|
||||
const fastify = require('fastify')({
|
||||
@@ -406,11 +398,10 @@ fastify.post('/foo', {
|
||||
#### Validator Compiler
|
||||
<a id="schema-validator"></a>
|
||||
|
||||
The `validatorCompiler` is a function that returns a function that validates the
|
||||
body, URL parameters, headers, and query string. The default
|
||||
`validatorCompiler` returns a function that implements the
|
||||
[ajv](https://ajv.js.org/) validation interface. Fastify uses it internally to
|
||||
speed the validation up.
|
||||
The `validatorCompiler` is a function that returns a function to validate the
|
||||
body, URL parameters, headers, and query string. The default `validatorCompiler`
|
||||
returns a function that implements the [ajv](https://ajv.js.org/) validation
|
||||
interface. Fastify uses it internally to speed up validation.
|
||||
|
||||
Fastify's [baseline ajv
|
||||
configuration](https://github.com/fastify/ajv-compiler#ajv-configuration) is:
|
||||
@@ -428,11 +419,11 @@ configuration](https://github.com/fastify/ajv-compiler#ajv-configuration) is:
|
||||
}
|
||||
```
|
||||
|
||||
This baseline configuration can be modified by providing
|
||||
[`ajv.customOptions`](./Server.md#factory-ajv) to your Fastify factory.
|
||||
Modify the baseline configuration by providing
|
||||
[`ajv.customOptions`](./Server.md#factory-ajv) to the Fastify factory.
|
||||
|
||||
If you want to change or set additional config options, you will need to create
|
||||
your own instance and override the existing one like:
|
||||
To change or set additional config options, create a custom instance and
|
||||
override the existing one:
|
||||
|
||||
```js
|
||||
const fastify = require('fastify')()
|
||||
@@ -448,29 +439,39 @@ fastify.setValidatorCompiler(({ schema, method, url, httpPart }) => {
|
||||
return ajv.compile(schema)
|
||||
})
|
||||
```
|
||||
_**Note:** If you use a custom instance of any validator (even Ajv), you have to
|
||||
add schemas to the validator instead of Fastify, since Fastify's default
|
||||
validator is no longer used, and Fastify's `addSchema` method has no idea what
|
||||
validator you are using._
|
||||
> ℹ️ Note: When using a custom validator instance, add schemas to the validator
|
||||
> instead of Fastify. Fastify's `addSchema` method will not recognize the custom
|
||||
> validator.
|
||||
|
||||
##### Using other validation libraries
|
||||
<a id="using-other-validation-libraries"></a>
|
||||
|
||||
The `setValidatorCompiler` function makes it easy to substitute `ajv` with
|
||||
almost any JavaScript validation library ([joi](https://github.com/hapijs/joi/),
|
||||
[yup](https://github.com/jquense/yup/), ...) or a custom one:
|
||||
The `setValidatorCompiler` function allows substituting `ajv` with other
|
||||
JavaScript validation libraries like [joi](https://github.com/hapijs/joi/) or
|
||||
[yup](https://github.com/jquense/yup/), or a custom one:
|
||||
|
||||
```js
|
||||
const Joi = require('joi')
|
||||
|
||||
fastify.setValidatorCompiler(({ schema }) => {
|
||||
return (data) => {
|
||||
try {
|
||||
const { error, value } = schema.validate(data)
|
||||
if (error) {
|
||||
return { error } // Return the error, do not throw it
|
||||
}
|
||||
return { value }
|
||||
} catch (e) {
|
||||
return { error: e } // Catch any unexpected errors too
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
fastify.post('/the/url', {
|
||||
schema: {
|
||||
body: Joi.object().keys({
|
||||
hello: Joi.string().required()
|
||||
}).required()
|
||||
},
|
||||
validatorCompiler: ({ schema, method, url, httpPart }) => {
|
||||
return data => schema.validate(data)
|
||||
}
|
||||
}, handler)
|
||||
```
|
||||
@@ -509,10 +510,44 @@ fastify.post('/the/url', {
|
||||
}, handler)
|
||||
```
|
||||
|
||||
##### Custom Validator Best Practices
|
||||
|
||||
When implementing custom validators, follow these patterns to ensure compatibility
|
||||
with all Fastify features:
|
||||
|
||||
** Always return objects, never throw:**
|
||||
```js
|
||||
return { value: validatedData } // On success
|
||||
return { error: validationError } // On failure
|
||||
```
|
||||
|
||||
** Use try-catch for safety:**
|
||||
```js
|
||||
fastify.setValidatorCompiler(({ schema }) => {
|
||||
return (data) => {
|
||||
try {
|
||||
// Validation logic here
|
||||
const result = schema.validate(data)
|
||||
if (result.error) {
|
||||
return { error: result.error }
|
||||
}
|
||||
return { value: result.value }
|
||||
} catch (e) {
|
||||
// Catch any unexpected errors
|
||||
return { error: e }
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
This pattern ensures validators work correctly with both sync and async
|
||||
`preValidation` hooks, preventing unhandled promise rejections that can crash
|
||||
an application.
|
||||
|
||||
##### .statusCode property
|
||||
|
||||
All validation errors will be added a `.statusCode` property set to `400`. This guarantees
|
||||
that the default error handler will set the status code of the response to `400`.
|
||||
All validation errors have a `.statusCode` property set to `400`, ensuring the
|
||||
default error handler sets the response status code to `400`.
|
||||
|
||||
```js
|
||||
fastify.setErrorHandler(function (error, request, reply) {
|
||||
@@ -525,30 +560,27 @@ fastify.setErrorHandler(function (error, request, reply) {
|
||||
|
||||
Fastify's validation error messages are tightly coupled to the default
|
||||
validation engine: errors returned from `ajv` are eventually run through the
|
||||
`schemaErrorFormatter` function which is responsible for building human-friendly
|
||||
error messages. However, the `schemaErrorFormatter` function is written with
|
||||
`ajv` in mind. As a result, you may run into odd or incomplete error messages
|
||||
when using other validation libraries.
|
||||
`schemaErrorFormatter` function which builds human-friendly error messages.
|
||||
However, the `schemaErrorFormatter` function is written with `ajv` in mind.
|
||||
This may result in odd or incomplete error messages when using other validation
|
||||
libraries.
|
||||
|
||||
To circumvent this issue, you have 2 main options :
|
||||
To circumvent this issue, there are two main options:
|
||||
|
||||
1. make sure your validation function (returned by your custom `schemaCompiler`)
|
||||
returns errors in the same structure and format as `ajv` (although this could
|
||||
prove to be difficult and tricky due to differences between validation
|
||||
engines)
|
||||
2. or use a custom `errorHandler` to intercept and format your 'custom'
|
||||
validation errors
|
||||
1. Ensure the validation function (returned by the custom `schemaCompiler`)
|
||||
returns errors in the same structure and format as `ajv`.
|
||||
2. Use a custom `errorHandler` to intercept and format custom validation errors.
|
||||
|
||||
To help you in writing a custom `errorHandler`, Fastify adds 2 properties to all
|
||||
validation errors:
|
||||
Fastify adds two properties to all validation errors to help write a custom
|
||||
`errorHandler`:
|
||||
|
||||
* `validation`: the content of the `error` property of the object returned by
|
||||
the validation function (returned by your custom `schemaCompiler`)
|
||||
* `validationContext`: the 'context' (body, params, query, headers) where the
|
||||
the validation function (returned by the custom `schemaCompiler`)
|
||||
* `validationContext`: the context (body, params, query, headers) where the
|
||||
validation error occurred
|
||||
|
||||
A very contrived example of such a custom `errorHandler` handling validation
|
||||
errors is shown below:
|
||||
A contrived example of such a custom `errorHandler` handling validation errors
|
||||
is shown below:
|
||||
|
||||
```js
|
||||
const errorHandler = (error, request, reply) => {
|
||||
@@ -560,9 +592,9 @@ const errorHandler = (error, request, reply) => {
|
||||
// check if we have a validation error
|
||||
if (validation) {
|
||||
response = {
|
||||
// validationContext will be 'body' or 'params' or 'headers' or 'query'
|
||||
// validationContext will be 'body', 'params', 'headers', or 'query'
|
||||
message: `A validation error occurred when validating the ${validationContext}...`,
|
||||
// this is the result of your validation library...
|
||||
// this is the result of the validation library...
|
||||
errors: validation
|
||||
}
|
||||
} else {
|
||||
@@ -581,12 +613,10 @@ const errorHandler = (error, request, reply) => {
|
||||
### Serialization
|
||||
<a id="serialization"></a>
|
||||
|
||||
Usually, you will send your data to the clients as JSON, and Fastify has a
|
||||
powerful tool to help you,
|
||||
[fast-json-stringify](https://www.npmjs.com/package/fast-json-stringify), which
|
||||
is used if you have provided an output schema in the route options. We encourage
|
||||
you to use an output schema, as it can drastically increase throughput and help
|
||||
prevent accidental disclosure of sensitive information.
|
||||
Fastify uses [fast-json-stringify](https://www.npmjs.com/package/fast-json-stringify)
|
||||
to send data as JSON if an output schema is provided in the route options. Using
|
||||
an output schema can drastically increase throughput and help prevent accidental
|
||||
disclosure of sensitive information.
|
||||
|
||||
Example:
|
||||
```js
|
||||
@@ -605,9 +635,8 @@ const schema = {
|
||||
fastify.post('/the/url', { schema }, handler)
|
||||
```
|
||||
|
||||
As you can see, the response schema is based on the status code. If you want to
|
||||
use the same schema for multiple status codes, you can use `'2xx'` or `default`,
|
||||
for example:
|
||||
The response schema is based on the status code. To use the same schema for
|
||||
multiple status codes, use `'2xx'` or `default`, for example:
|
||||
```js
|
||||
const schema = {
|
||||
response: {
|
||||
@@ -636,41 +665,51 @@ const schema = {
|
||||
|
||||
fastify.post('/the/url', { schema }, handler)
|
||||
```
|
||||
You can even have a specific response schema for different content types.
|
||||
A specific response schema can be defined for different content types.
|
||||
For example:
|
||||
```js
|
||||
const schema = {
|
||||
response: {
|
||||
200: {
|
||||
description: 'Response schema that support different content types'
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
name: { type: 'string' },
|
||||
image: { type: 'string' },
|
||||
address: { type: 'string' }
|
||||
}
|
||||
},
|
||||
'application/vnd.v1+json': {
|
||||
schema: {
|
||||
type: 'array',
|
||||
items: { $ref: 'test' }
|
||||
}
|
||||
}
|
||||
response: {
|
||||
200: {
|
||||
description: 'Response schema that support different content types'
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
name: { type: 'string' },
|
||||
image: { type: 'string' },
|
||||
address: { type: 'string' }
|
||||
}
|
||||
},
|
||||
'3xx': {
|
||||
content: {
|
||||
'application/vnd.v2+json': {
|
||||
schema: {
|
||||
fullName: { type: 'string' },
|
||||
phone: { type: 'string' }
|
||||
}
|
||||
}
|
||||
'application/vnd.v1+json': {
|
||||
schema: {
|
||||
type: 'array',
|
||||
items: { $ref: 'test' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'3xx': {
|
||||
content: {
|
||||
'application/vnd.v2+json': {
|
||||
schema: {
|
||||
fullName: { type: 'string' },
|
||||
phone: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
default: {
|
||||
content: {
|
||||
// */* is match-all content-type
|
||||
'*/*': {
|
||||
schema: {
|
||||
desc: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fastify.post('/url', { schema }, handler)
|
||||
```
|
||||
@@ -678,10 +717,9 @@ fastify.post('/url', { schema }, handler)
|
||||
#### Serializer Compiler
|
||||
<a id="schema-serializer"></a>
|
||||
|
||||
The `serializerCompiler` is a function that returns a function that must return
|
||||
a string from an input object. When you define a response JSON Schema, you can
|
||||
change the default serialization method by providing a function to serialize
|
||||
every route where you do.
|
||||
The `serializerCompiler` returns a function that must return a string from an
|
||||
input object. When defining a response JSON Schema, change the default
|
||||
serialization method by providing a function to serialize each route.
|
||||
|
||||
```js
|
||||
fastify.setSerializerCompiler(({ schema, method, url, httpStatus, contentType }) => {
|
||||
@@ -695,21 +733,24 @@ fastify.get('/user', {
|
||||
schema: {
|
||||
response: {
|
||||
'2xx': {
|
||||
id: { type: 'number' },
|
||||
name: { type: 'string' }
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'number' },
|
||||
name: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
*If you need a custom serializer in a very specific part of your code, you can
|
||||
set one with [`reply.serializer(...)`](./Reply.md#serializerfunc).*
|
||||
*To set a custom serializer in a specific part of the code, use
|
||||
[`reply.serializer(...)`](./Reply.md#serializerfunc).*
|
||||
|
||||
### Error Handling
|
||||
When schema validation fails for a request, Fastify will automatically return a
|
||||
status 400 response including the result from the validator in the payload. As
|
||||
an example, if you have the following schema for your route
|
||||
status 400 response including the result from the validator in the payload. For
|
||||
example, if the following schema is used for a route:
|
||||
|
||||
```js
|
||||
const schema = {
|
||||
@@ -723,8 +764,8 @@ const schema = {
|
||||
}
|
||||
```
|
||||
|
||||
and fail to satisfy it, the route will immediately return a response with the
|
||||
following payload
|
||||
If the request fails to satisfy the schema, the route will return a response
|
||||
with the following payload:
|
||||
|
||||
```js
|
||||
{
|
||||
@@ -734,10 +775,15 @@ following payload
|
||||
}
|
||||
```
|
||||
|
||||
If you want to handle errors inside the route, you can specify the
|
||||
`attachValidation` option for your route. If there is a _validation error_, the
|
||||
`validationError` property of the request will contain the `Error` object with
|
||||
the raw `validation` result as shown below
|
||||
> ⚠ Security Consideration: By default, validation error details from the schema
|
||||
> are included in the response payload. If your organization requires sanitizing
|
||||
> or customizing these error messages (e.g., to avoid exposing internal schema
|
||||
> details), configure a custom error handler using
|
||||
> [`setErrorHandler()`](./Server.md#seterrorhandler).
|
||||
|
||||
To handle errors inside the route, specify the `attachValidation` option. If
|
||||
there is a validation error, the `validationError` property of the request will
|
||||
contain the `Error` object with the raw validation result as shown below:
|
||||
|
||||
```js
|
||||
const fastify = Fastify()
|
||||
@@ -752,13 +798,13 @@ fastify.post('/', { schema, attachValidation: true }, function (req, reply) {
|
||||
|
||||
#### `schemaErrorFormatter`
|
||||
|
||||
If you want to format errors yourself, you can provide a sync function that must
|
||||
return an error as the `schemaErrorFormatter` option to Fastify when
|
||||
instantiating. The context function will be the Fastify server instance.
|
||||
To format errors, provide a sync function that returns an error as the
|
||||
`schemaErrorFormatter` option when instantiating Fastify. The context function
|
||||
will be the Fastify server instance.
|
||||
|
||||
`errors` is an array of Fastify schema errors `FastifySchemaValidationError`.
|
||||
`dataVar` is the currently validated part of the schema. (params | body |
|
||||
querystring | headers).
|
||||
`dataVar` is the currently validated part of the schema (params, body,
|
||||
querystring, headers).
|
||||
|
||||
```js
|
||||
const fastify = Fastify({
|
||||
@@ -776,8 +822,8 @@ fastify.setSchemaErrorFormatter(function (errors, dataVar) {
|
||||
})
|
||||
```
|
||||
|
||||
You can also use [setErrorHandler](./Server.md#seterrorhandler) to define a
|
||||
custom response for validation errors such as
|
||||
Use [setErrorHandler](./Server.md#seterrorhandler) to define a custom response
|
||||
for validation errors such as:
|
||||
|
||||
```js
|
||||
fastify.setErrorHandler(function (error, request, reply) {
|
||||
@@ -787,25 +833,25 @@ fastify.setErrorHandler(function (error, request, reply) {
|
||||
})
|
||||
```
|
||||
|
||||
If you want a custom error response in the schema without headaches, and
|
||||
quickly, take a look at
|
||||
For custom error responses in the schema, see
|
||||
[`ajv-errors`](https://github.com/epoberezkin/ajv-errors). Check out the
|
||||
[example](https://github.com/fastify/example/blob/HEAD/validation-messages/custom-errors-messages.js)
|
||||
usage.
|
||||
> Make sure to install version 1.0.1 of `ajv-errors`, because later versions of
|
||||
> it are not compatible with AJV v6 (the version shipped by Fastify v3).
|
||||
|
||||
> Install version 1.0.1 of `ajv-errors`, as later versions are not compatible
|
||||
> with AJV v6 (the version shipped by Fastify v3).
|
||||
|
||||
Below is an example showing how to add **custom error messages for each
|
||||
property** of a schema by supplying custom AJV options. Inline comments in the
|
||||
schema below describe how to configure it to show a different error message for
|
||||
each case:
|
||||
schema describe how to configure it to show a different error message for each
|
||||
case:
|
||||
|
||||
```js
|
||||
const fastify = Fastify({
|
||||
ajv: {
|
||||
customOptions: {
|
||||
jsonPointers: true,
|
||||
// Warning: Enabling this option may lead to this security issue https://www.cvedetails.com/cve/CVE-2020-8192/
|
||||
// ⚠ Warning: Enabling this option may lead to this security issue https://www.cvedetails.com/cve/CVE-2020-8192/
|
||||
allErrors: true
|
||||
},
|
||||
plugins: [
|
||||
@@ -849,8 +895,8 @@ fastify.post('/', { schema, }, (request, reply) => {
|
||||
})
|
||||
```
|
||||
|
||||
If you want to return localized error messages, take a look at
|
||||
[ajv-i18n](https://github.com/epoberezkin/ajv-i18n)
|
||||
To return localized error messages, see
|
||||
[ajv-i18n](https://github.com/epoberezkin/ajv-i18n).
|
||||
|
||||
```js
|
||||
const localize = require('ajv-i18n')
|
||||
@@ -884,8 +930,8 @@ fastify.setErrorHandler(function (error, request, reply) {
|
||||
|
||||
### JSON Schema support
|
||||
|
||||
JSON Schema provides utilities to optimize your schemas that, in conjunction
|
||||
with Fastify's shared schema, let you reuse all your schemas easily.
|
||||
JSON Schema provides utilities to optimize schemas. Combined with Fastify's
|
||||
shared schema, all schemas can be easily reused.
|
||||
|
||||
| Use Case | Validator | Serializer |
|
||||
|-----------------------------------|-----------|------------|
|
||||
@@ -992,11 +1038,11 @@ const refToSharedSchemaDefinitions = {
|
||||
|
||||
- [JSON Schema](https://json-schema.org/)
|
||||
- [Understanding JSON
|
||||
Schema](https://spacetelescope.github.io/understanding-json-schema/)
|
||||
Schema](https://json-schema.org/understanding-json-schema/about)
|
||||
- [fast-json-stringify
|
||||
documentation](https://github.com/fastify/fast-json-stringify)
|
||||
- [Ajv documentation](https://github.com/epoberezkin/ajv/blob/master/README.md)
|
||||
- [Ajv i18n](https://github.com/epoberezkin/ajv-i18n)
|
||||
- [Ajv custom errors](https://github.com/epoberezkin/ajv-errors)
|
||||
- Custom error handling with core methods with error file dumping
|
||||
[example](https://github.com/fastify/example/tree/master/validation-messages)
|
||||
[example](https://github.com/fastify/example/tree/main/validation-messages)
|
||||
|
||||
76
backend/node_modules/fastify/docs/Reference/Warnings.md
generated
vendored
76
backend/node_modules/fastify/docs/Reference/Warnings.md
generated
vendored
@@ -8,54 +8,33 @@
|
||||
- [FSTWRN001](#FSTWRN001)
|
||||
- [FSTWRN002](#FSTWRN002)
|
||||
- [Fastify Deprecation Codes](#fastify-deprecation-codes)
|
||||
- [FSTDEP005](#FSTDEP005)
|
||||
- [FSTDEP006](#FSTDEP006)
|
||||
- [FSTDEP007](#FSTDEP007)
|
||||
- [FSTDEP008](#FSTDEP008)
|
||||
- [FSTDEP009](#FSTDEP009)
|
||||
- [FSTDEP010](#FSTDEP010)
|
||||
- [FSTDEP011](#FSTDEP011)
|
||||
- [FSTDEP012](#FSTDEP012)
|
||||
- [FSTDEP013](#FSTDEP013)
|
||||
- [FSTDEP014](#FSTDEP014)
|
||||
- [FSTDEP015](#FSTDEP015)
|
||||
- [FSTDEP016](#FSTDEP016)
|
||||
- [FSTDEP017](#FSTDEP017)
|
||||
- [FSTDEP018](#FSTDEP018)
|
||||
- [FSTDEP019](#FSTDEP019)
|
||||
- [FSTDEP020](#FSTDEP020)
|
||||
- [FSTDEP021](#FSTDEP021)
|
||||
- [FSTDEP022](#FSTDEP022)
|
||||
|
||||
|
||||
## Warnings
|
||||
|
||||
### Warnings In Fastify
|
||||
|
||||
Fastify utilizes Node.js's [warning event](https://nodejs.org/api/process.html#event-warning)
|
||||
API to notify users of deprecated features and known coding mistakes. Fastify's
|
||||
warnings are recognizable by the `FSTWRN` and `FSTDEP` prefixes on warning
|
||||
code. When encountering such a warning, it is highly recommended that the
|
||||
cause of the warning be determined through use of the
|
||||
[`--trace-warnings`](https://nodejs.org/api/cli.html#--trace-warnings) and
|
||||
[`--trace-deprecation`](https://nodejs.org/api/cli.html#--trace-deprecation)
|
||||
flags. These will produce stack traces pointing out where the issue occurs
|
||||
in the application's code. Issues opened about warnings without including
|
||||
this information may be closed due to lack of information.
|
||||
Fastify uses Node.js's [warning event](https://nodejs.org/api/process.html#event-warning)
|
||||
API to notify users of deprecated features and coding mistakes. Fastify's
|
||||
warnings are recognizable by the `FSTWRN` and `FSTDEP` prefixes. When
|
||||
encountering such a warning, it is highly recommended to determine the cause
|
||||
using the [`--trace-warnings`](https://nodejs.org/api/cli.html#--trace-warnings)
|
||||
and [`--trace-deprecation`](https://nodejs.org/api/cli.html#--trace-deprecation)
|
||||
flags. These produce stack traces pointing to where the issue occurs in the
|
||||
application's code. Issues opened about warnings without this information will
|
||||
be closed due to lack of details.
|
||||
|
||||
In addition to tracing, warnings can also be disabled. It is not recommended to
|
||||
disable warnings as a matter of course, but if necessary, they can be disabled
|
||||
by using any of the following methods:
|
||||
Warnings can also be disabled, though it is not recommended. If necessary, use
|
||||
one of the following methods:
|
||||
|
||||
- setting the `NODE_NO_WARNINGS` environment variable to `1`
|
||||
- passing the `--no-warnings` flag to the node process
|
||||
- setting 'no-warnings' in the `NODE_OPTIONS` environment variable
|
||||
- Set the `NODE_NO_WARNINGS` environment variable to `1`
|
||||
- Pass the `--no-warnings` flag to the node process
|
||||
- Set `no-warnings` in the `NODE_OPTIONS` environment variable
|
||||
|
||||
For more information on how to disable warnings, see [node's documentation](https://nodejs.org/api/cli.html).
|
||||
For more information on disabling warnings, see [Node's documentation](https://nodejs.org/api/cli.html).
|
||||
|
||||
However, disabling warnings is not recommended as it may cause
|
||||
potential problems when upgrading Fastify versions.
|
||||
Only experienced users should consider disabling warnings.
|
||||
Disabling warnings may cause issues when upgrading Fastify versions. Only
|
||||
experienced users should consider disabling warnings.
|
||||
|
||||
### Fastify Warning Codes
|
||||
|
||||
@@ -67,7 +46,7 @@ Only experienced users should consider disabling warnings.
|
||||
|
||||
### Fastify Deprecation Codes
|
||||
|
||||
Deprecation codes are further supported by the Node.js CLI options:
|
||||
Deprecation codes are supported by the Node.js CLI options:
|
||||
|
||||
- [--no-deprecation](https://nodejs.org/api/cli.html#--no-deprecation)
|
||||
- [--throw-deprecation](https://nodejs.org/api/cli.html#--throw-deprecation)
|
||||
@@ -76,21 +55,4 @@ Deprecation codes are further supported by the Node.js CLI options:
|
||||
|
||||
| Code | Description | How to solve | Discussion |
|
||||
| ---- | ----------- | ------------ | ---------- |
|
||||
| <a id="FSTDEP005">FSTDEP005</a> | You are accessing the deprecated `request.connection` property. | Use `request.socket`. | [#2594](https://github.com/fastify/fastify/pull/2594) |
|
||||
| <a id="FSTDEP006">FSTDEP006</a> | You are decorating Request/Reply with a reference type. This reference is shared amongst all requests. | Do not use Arrays/Objects as values when decorating Request/Reply. | [#2688](https://github.com/fastify/fastify/pull/2688) |
|
||||
| <a id="FSTDEP007">FSTDEP007</a> | You are trying to set a HEAD route using `exposeHeadRoute` route flag when a sibling route is already set. | Remove `exposeHeadRoutes` or explicitly set `exposeHeadRoutes` to `false` | [#2700](https://github.com/fastify/fastify/pull/2700) |
|
||||
| <a id="FSTDEP008">FSTDEP008</a> | You are using route constraints via the route `{version: "..."}` option. | Use `{constraints: {version: "..."}}` option. | [#2682](https://github.com/fastify/fastify/pull/2682) |
|
||||
| <a id="FSTDEP009">FSTDEP009</a> | You are using a custom route versioning strategy via the server `{versioning: "..."}` option. | Use `{constraints: {version: "..."}}` option. | [#2682](https://github.com/fastify/fastify/pull/2682) |
|
||||
| <a id="FSTDEP010">FSTDEP010</a> | Modifying the `reply.sent` property is deprecated. | Use the `reply.hijack()` method. | [#3140](https://github.com/fastify/fastify/pull/3140) |
|
||||
| <a id="FSTDEP011">FSTDEP011</a> | Variadic listen method is deprecated. | Use `.listen(optionsObject)`. | [#3712](https://github.com/fastify/fastify/pull/3712) |
|
||||
| <a id="FSTDEP012">FSTDEP012</a> | You are trying to access the deprecated `request.context` property. | Use `request.routeOptions.config` or `request.routeOptions.schema`. | [#4216](https://github.com/fastify/fastify/pull/4216) [#5084](https://github.com/fastify/fastify/pull/5084) |
|
||||
| <a id="FSTDEP013">FSTDEP013</a> | Direct return of "trailers" function is deprecated. | Use "callback" or "async-await" for return value. | [#4380](https://github.com/fastify/fastify/pull/4380) |
|
||||
| <a id="FSTDEP014">FSTDEP014</a> | You are trying to set/access the default route. This property is deprecated. | Use `setNotFoundHandler` if you want to custom a 404 handler or the wildcard (`*`) to match all routes. | [#4480](https://github.com/fastify/fastify/pull/4480) |
|
||||
| <a id="FSTDEP015">FSTDEP015</a> | You are accessing the deprecated `request.routeSchema` property. | Use `request.routeOptions.schema`. | [#4470](https://github.com/fastify/fastify/pull/4470) |
|
||||
| <a id="FSTDEP016">FSTDEP016</a> | You are accessing the deprecated `request.routeConfig` property. | Use `request.routeOptions.config`. | [#4470](https://github.com/fastify/fastify/pull/4470) |
|
||||
| <a id="FSTDEP017">FSTDEP017</a> | You are accessing the deprecated `request.routerPath` property. | Use `request.routeOptions.url`. | [#4470](https://github.com/fastify/fastify/pull/4470) |
|
||||
| <a id="FSTDEP018">FSTDEP018</a> | You are accessing the deprecated `request.routerMethod` property. | Use `request.routeOptions.method`. | [#4470](https://github.com/fastify/fastify/pull/4470) |
|
||||
| <a id="FSTDEP019">FSTDEP019</a> | You are accessing the deprecated `reply.context` property. | Use `reply.routeOptions.config` or `reply.routeOptions.schema`. | [#5032](https://github.com/fastify/fastify/pull/5032) [#5084](https://github.com/fastify/fastify/pull/5084) |
|
||||
| <a id="FSTDEP020">FSTDEP020</a> | You are using the deprecated `reply.getReponseTime()` method. | Use the `reply.elapsedTime` property instead. | [#5263](https://github.com/fastify/fastify/pull/5263) |
|
||||
| <a id="FSTDEP021">FSTDEP021</a> | The `reply.redirect()` method has a new signature: `reply.redirect(url: string, code?: number)`. It will be enforced in `fastify@v5`'. | [#5483](https://github.com/fastify/fastify/pull/5483) |
|
||||
| <a id="FSTDEP022">FSTDEP022</a> | You are using the deprecated json shorthand schema on route %s. Specify full object schema instead. It will be removed in `fastify@v5` | [#5483](https://github.com/fastify/fastify/pull/0000) |
|
||||
| <a id="FSTDEP022">FSTDEP022</a> | You are trying to access the deprecated router options on top option properties. | Use `options.routerOptions`. | [#5985](https://github.com/fastify/fastify/pull/5985)
|
||||
|
||||
35
backend/node_modules/fastify/eslint.config.js
generated
vendored
Normal file
35
backend/node_modules/fastify/eslint.config.js
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
'use strict'
|
||||
const neostandard = require('neostandard')
|
||||
|
||||
module.exports = [
|
||||
...neostandard({
|
||||
ignores: [
|
||||
'lib/config-validator.js',
|
||||
'lib/error-serializer.js',
|
||||
'test/same-shape.test.js',
|
||||
'test/types/import.js'
|
||||
],
|
||||
ts: true
|
||||
}),
|
||||
{
|
||||
rules: {
|
||||
'comma-dangle': ['error', 'never'],
|
||||
'max-len': ['error', {
|
||||
code: 120,
|
||||
tabWidth: 2,
|
||||
ignoreUrls: true,
|
||||
ignoreStrings: true,
|
||||
ignoreTemplateLiterals: true,
|
||||
ignoreRegExpLiterals: true,
|
||||
ignoreComments: true,
|
||||
ignoreTrailingComments: true
|
||||
}]
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['**/*.d.ts'],
|
||||
rules: {
|
||||
'max-len': 'off'
|
||||
}
|
||||
}
|
||||
]
|
||||
27
backend/node_modules/fastify/examples/benchmark/webstream.js
generated
vendored
Normal file
27
backend/node_modules/fastify/examples/benchmark/webstream.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
'use strict'
|
||||
|
||||
const fastify = require('../../fastify')({
|
||||
logger: false
|
||||
})
|
||||
|
||||
const payload = JSON.stringify({ hello: 'world' })
|
||||
|
||||
fastify.get('/', function (req, reply) {
|
||||
const stream = new ReadableStream({
|
||||
start (controller) {
|
||||
controller.enqueue(payload)
|
||||
controller.close()
|
||||
}
|
||||
})
|
||||
return new Response(stream, {
|
||||
status: 200,
|
||||
headers: {
|
||||
'content-type': 'application/json; charset=utf-8'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
fastify.listen({ port: 3000 }, (err, address) => {
|
||||
if (err) throw err
|
||||
console.log(`Server listening on ${address}`)
|
||||
})
|
||||
28
backend/node_modules/fastify/examples/typescript-server.ts
generated
vendored
28
backend/node_modules/fastify/examples/typescript-server.ts
generated
vendored
@@ -10,8 +10,8 @@
|
||||
* node examples/typescript-server.js
|
||||
*/
|
||||
|
||||
import fastify, { FastifyInstance, RouteShorthandOptions } from '../fastify';
|
||||
import { Server, IncomingMessage, ServerResponse } from 'http';
|
||||
import fastify, { FastifyInstance, RouteShorthandOptions } from '../fastify'
|
||||
import { Server, IncomingMessage, ServerResponse } from 'node:http'
|
||||
|
||||
// Create an http server. We pass the relevant typings for our http version used.
|
||||
// By passing types we get correctly typed access to the underlying http objects in routes.
|
||||
@@ -20,7 +20,7 @@ const server: FastifyInstance<
|
||||
Server,
|
||||
IncomingMessage,
|
||||
ServerResponse
|
||||
> = fastify({ logger: true });
|
||||
> = fastify({ logger: true })
|
||||
|
||||
// Define interfaces for our request. We can create these automatically
|
||||
// off our JSON Schema files (See TypeScript.md) but for the purpose of this
|
||||
@@ -53,7 +53,7 @@ const opts: RouteShorthandOptions = {
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Add our route handler with correct types
|
||||
server.post<{
|
||||
@@ -62,18 +62,18 @@ server.post<{
|
||||
Headers: PingHeaders;
|
||||
Body: PingBody;
|
||||
}>('/ping/:bar', opts, (request, reply) => {
|
||||
console.log(request.query); // this is of type `PingQuerystring`
|
||||
console.log(request.params); // this is of type `PingParams`
|
||||
console.log(request.headers); // this is of type `PingHeaders`
|
||||
console.log(request.body); // this is of type `PingBody`
|
||||
reply.code(200).send({ pong: 'it worked!' });
|
||||
});
|
||||
console.log(request.query) // this is of type `PingQuerystring`
|
||||
console.log(request.params) // this is of type `PingParams`
|
||||
console.log(request.headers) // this is of type `PingHeaders`
|
||||
console.log(request.body) // this is of type `PingBody`
|
||||
reply.code(200).send({ pong: 'it worked!' })
|
||||
})
|
||||
|
||||
// Start your server
|
||||
server.listen({ port: 8080 }, (err, address) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
}
|
||||
console.log(`server listening on ${address}`)
|
||||
});
|
||||
console.log(`server listening on ${address}`)
|
||||
})
|
||||
|
||||
112
backend/node_modules/fastify/fastify.d.ts
generated
vendored
112
backend/node_modules/fastify/fastify.d.ts
generated
vendored
@@ -1,29 +1,37 @@
|
||||
import * as http from 'http'
|
||||
import * as http2 from 'http2'
|
||||
import * as https from 'https'
|
||||
import { Socket } from 'net'
|
||||
import * as http from 'node:http'
|
||||
import * as http2 from 'node:http2'
|
||||
import * as https from 'node:https'
|
||||
import { Socket } from 'node:net'
|
||||
|
||||
import { Options as AjvOptions, ValidatorFactory } from '@fastify/ajv-compiler'
|
||||
import { BuildCompilerFromPool, ValidatorFactory } from '@fastify/ajv-compiler'
|
||||
import { FastifyError } from '@fastify/error'
|
||||
import { Options as FJSOptions, SerializerFactory } from '@fastify/fast-json-stringify-compiler'
|
||||
import { ConstraintStrategy, HTTPVersion } from 'find-my-way'
|
||||
import { Chain as LightMyRequestChain, InjectOptions, Response as LightMyRequestResponse, CallbackFunc as LightMyRequestCallback } from 'light-my-request'
|
||||
import { Config as FindMyWayConfig, ConstraintStrategy, HTTPVersion } from 'find-my-way'
|
||||
import { InjectOptions, CallbackFunc as LightMyRequestCallback, Chain as LightMyRequestChain, Response as LightMyRequestResponse } from 'light-my-request'
|
||||
|
||||
import { FastifyBodyParser, FastifyContentTypeParser, AddContentTypeParser, hasContentTypeParser, getDefaultJsonParser, ProtoAction, ConstructorAction } from './types/content-type-parser'
|
||||
import { FastifyRequestContext, FastifyContextConfig, FastifyReplyContext } from './types/context'
|
||||
import { AddContentTypeParser, ConstructorAction, FastifyBodyParser, FastifyContentTypeParser, getDefaultJsonParser, hasContentTypeParser, ProtoAction } from './types/content-type-parser'
|
||||
import { FastifyContextConfig, FastifyReplyContext, FastifyRequestContext } from './types/context'
|
||||
import { FastifyErrorCodes } from './types/errors'
|
||||
import { DoneFuncWithErrOrRes, HookHandlerDoneFunction, RequestPayload, onCloseAsyncHookHandler, onCloseHookHandler, onErrorAsyncHookHandler, onErrorHookHandler, onReadyAsyncHookHandler, onReadyHookHandler, onListenAsyncHookHandler, onListenHookHandler, onRegisterHookHandler, onRequestAsyncHookHandler, onRequestHookHandler, onResponseAsyncHookHandler, onResponseHookHandler, onRouteHookHandler, onSendAsyncHookHandler, onSendHookHandler, onTimeoutAsyncHookHandler, onTimeoutHookHandler, preHandlerAsyncHookHandler, preHandlerHookHandler, preParsingAsyncHookHandler, preParsingHookHandler, preSerializationAsyncHookHandler, preSerializationHookHandler, preValidationAsyncHookHandler, preValidationHookHandler, onRequestAbortHookHandler, onRequestAbortAsyncHookHandler, preCloseAsyncHookHandler, preCloseHookHandler } from './types/hooks'
|
||||
import { FastifyListenOptions, FastifyInstance, PrintRoutesOptions } from './types/instance'
|
||||
import { FastifyBaseLogger, FastifyLoggerInstance, FastifyLoggerOptions, PinoLoggerOptions, FastifyLogFn, LogLevel } from './types/logger'
|
||||
import { FastifyPluginCallback, FastifyPluginAsync, FastifyPluginOptions, FastifyPlugin } from './types/plugin'
|
||||
import { DoneFuncWithErrOrRes, HookHandlerDoneFunction, onCloseAsyncHookHandler, onCloseHookHandler, onErrorAsyncHookHandler, onErrorHookHandler, onListenAsyncHookHandler, onListenHookHandler, onReadyAsyncHookHandler, onReadyHookHandler, onRegisterHookHandler, onRequestAbortAsyncHookHandler, onRequestAbortHookHandler, onRequestAsyncHookHandler, onRequestHookHandler, onResponseAsyncHookHandler, onResponseHookHandler, onRouteHookHandler, onSendAsyncHookHandler, onSendHookHandler, onTimeoutAsyncHookHandler, onTimeoutHookHandler, preCloseAsyncHookHandler, preCloseHookHandler, preHandlerAsyncHookHandler, preHandlerHookHandler, preParsingAsyncHookHandler, preParsingHookHandler, preSerializationAsyncHookHandler, preSerializationHookHandler, preValidationAsyncHookHandler, preValidationHookHandler, RequestPayload } from './types/hooks'
|
||||
import { FastifyInstance, FastifyListenOptions, PrintRoutesOptions } from './types/instance'
|
||||
import {
|
||||
FastifyBaseLogger,
|
||||
FastifyChildLoggerFactory,
|
||||
FastifyLogFn,
|
||||
FastifyLoggerInstance,
|
||||
FastifyLoggerOptions,
|
||||
LogLevel,
|
||||
PinoLoggerOptions
|
||||
} from './types/logger'
|
||||
import { FastifyPlugin, FastifyPluginAsync, FastifyPluginCallback, FastifyPluginOptions } from './types/plugin'
|
||||
import { FastifyRegister, FastifyRegisterOptions, RegisterOptions } from './types/register'
|
||||
import { FastifyReply } from './types/reply'
|
||||
import { FastifyRequest, RequestGenericInterface } from './types/request'
|
||||
import { RouteHandler, RouteHandlerMethod, RouteOptions, RouteShorthandMethod, RouteShorthandOptions, RouteShorthandOptionsWithHandler, RouteGenericInterface } from './types/route'
|
||||
import { FastifySchema, FastifySchemaCompiler, FastifySchemaValidationError, SchemaErrorDataVar, SchemaErrorFormatter } from './types/schema'
|
||||
import { FastifyServerFactory, FastifyServerFactoryHandler } from './types/serverFactory'
|
||||
import { FastifyTypeProvider, FastifyTypeProviderDefault } from './types/type-provider'
|
||||
import { HTTPMethods, RawServerBase, RawRequestDefaultExpression, RawReplyDefaultExpression, RawServerDefault, ContextConfigDefault, RequestBodyDefault, RequestQuerystringDefault, RequestParamsDefault, RequestHeadersDefault } from './types/utils'
|
||||
import { RouteGenericInterface, RouteHandler, RouteHandlerMethod, RouteOptions, RouteShorthandMethod, RouteShorthandOptions, RouteShorthandOptionsWithHandler } from './types/route'
|
||||
import { FastifySchema, FastifySchemaValidationError, FastifySchemaCompiler, FastifySerializerCompiler, SchemaErrorDataVar, SchemaErrorFormatter } from './types/schema'
|
||||
import { FastifyServerFactory, FastifyServerFactoryHandler } from './types/server-factory'
|
||||
import { FastifyTypeProvider, FastifyTypeProviderDefault, SafePromiseLike } from './types/type-provider'
|
||||
import { ContextConfigDefault, HTTPMethods, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerBase, RawServerDefault, RequestBodyDefault, RequestHeadersDefault, RequestParamsDefault, RequestQuerystringDefault } from './types/utils'
|
||||
|
||||
declare module '@fastify/error' {
|
||||
interface FastifyError {
|
||||
@@ -35,7 +43,7 @@ declare module '@fastify/error' {
|
||||
type Fastify = typeof fastify
|
||||
|
||||
declare namespace fastify {
|
||||
export const errorCodes: FastifyErrorCodes;
|
||||
export const errorCodes: FastifyErrorCodes
|
||||
|
||||
export type FastifyHttp2SecureOptions<
|
||||
Server extends http2.Http2SecureServer,
|
||||
@@ -69,6 +77,7 @@ declare namespace fastify {
|
||||
}
|
||||
|
||||
type FindMyWayVersion<RawServer extends RawServerBase> = RawServer extends http.Server ? HTTPVersion.V1 : HTTPVersion.V2
|
||||
type FindMyWayConfigForServer<RawServer extends RawServerBase> = FindMyWayConfig<FindMyWayVersion<RawServer>>
|
||||
|
||||
export interface ConnectionError extends Error {
|
||||
code: string,
|
||||
@@ -81,6 +90,19 @@ declare namespace fastify {
|
||||
|
||||
type TrustProxyFunction = (address: string, hop: number) => boolean
|
||||
|
||||
export type FastifyRouterOptions<RawServer extends RawServerBase> = Omit<FindMyWayConfigForServer<RawServer>, 'defaultRoute' | 'onBadUrl' | 'querystringParser'> & {
|
||||
defaultRoute?: (
|
||||
req: RawRequestDefaultExpression<RawServer>,
|
||||
res: RawReplyDefaultExpression<RawServer>
|
||||
) => void,
|
||||
onBadUrl?: (
|
||||
path: string,
|
||||
req: RawRequestDefaultExpression<RawServer>,
|
||||
res: RawReplyDefaultExpression<RawServer>
|
||||
) => void,
|
||||
querystringParser?: (str: string) => { [key: string]: unknown }
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for a fastify server instance. Utilizes conditional logic on the generic server parameter to enforce certain https and http2
|
||||
*/
|
||||
@@ -98,11 +120,12 @@ declare namespace fastify {
|
||||
pluginTimeout?: number,
|
||||
bodyLimit?: number,
|
||||
maxParamLength?: number,
|
||||
disableRequestLogging?: boolean,
|
||||
disableRequestLogging?: boolean | ((req: FastifyRequest) => boolean),
|
||||
exposeHeadRoutes?: boolean,
|
||||
onProtoPoisoning?: ProtoAction,
|
||||
onConstructorPoisoning?: ConstructorAction,
|
||||
logger?: boolean | FastifyLoggerOptions<RawServer> & PinoLoggerOptions | Logger,
|
||||
logger?: boolean | FastifyLoggerOptions<RawServer> & PinoLoggerOptions,
|
||||
loggerInstance?: Logger
|
||||
serializerOpts?: FJSOptions | Record<string, unknown>,
|
||||
serverFactory?: FastifyServerFactory<RawServer>,
|
||||
caseSensitive?: boolean,
|
||||
@@ -110,22 +133,9 @@ declare namespace fastify {
|
||||
requestIdHeader?: string | false,
|
||||
requestIdLogLabel?: string;
|
||||
useSemicolonDelimiter?: boolean,
|
||||
jsonShorthand?: boolean;
|
||||
genReqId?: (req: RawRequestDefaultExpression<RawServer>) => string,
|
||||
trustProxy?: boolean | string | string[] | number | TrustProxyFunction,
|
||||
querystringParser?: (str: string) => { [key: string]: unknown },
|
||||
/**
|
||||
* @deprecated Prefer using the `constraints.version` property
|
||||
*/
|
||||
versioning?: {
|
||||
storage(): {
|
||||
get(version: string): string | null,
|
||||
set(version: string, store: Function): void
|
||||
del(version: string): void,
|
||||
empty(): void
|
||||
},
|
||||
deriveVersion<Context>(req: Object, ctx?: Context): string // not a fan of using Object here. Also what is Context? Can either of these be better defined?
|
||||
},
|
||||
constraints?: {
|
||||
[name: string]: ConstraintStrategy<FindMyWayVersion<RawServer>, unknown>,
|
||||
},
|
||||
@@ -141,14 +151,11 @@ declare namespace fastify {
|
||||
};
|
||||
};
|
||||
return503OnClosing?: boolean,
|
||||
ajv?: {
|
||||
customOptions?: AjvOptions,
|
||||
plugins?: (Function | [Function, unknown])[]
|
||||
},
|
||||
ajv?: Parameters<BuildCompilerFromPool>[1],
|
||||
frameworkErrors?: <RequestGeneric extends RequestGenericInterface = RequestGenericInterface, TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault, SchemaCompiler extends FastifySchema = FastifySchema>(
|
||||
error: FastifyError,
|
||||
req: FastifyRequest<RequestGeneric, RawServer, RawRequestDefaultExpression<RawServer>, FastifySchema, TypeProvider>,
|
||||
res: FastifyReply<RawServer, RawRequestDefaultExpression<RawServer>, RawReplyDefaultExpression<RawServer>, RequestGeneric, FastifyContextConfig, SchemaCompiler, TypeProvider>
|
||||
res: FastifyReply<RequestGeneric, RawServer, RawRequestDefaultExpression<RawServer>, RawReplyDefaultExpression<RawServer>, FastifyContextConfig, SchemaCompiler, TypeProvider>
|
||||
) => void,
|
||||
rewriteUrl?: (
|
||||
// The RawRequestDefaultExpression, RawReplyDefaultExpression, and FastifyTypeProviderDefault parameters
|
||||
@@ -161,12 +168,15 @@ declare namespace fastify {
|
||||
* listener to error events emitted by client connections
|
||||
*/
|
||||
clientErrorHandler?: (error: ConnectionError, socket: Socket) => void,
|
||||
childLoggerFactory?: FastifyChildLoggerFactory,
|
||||
allowErrorHandlerOverride?: boolean
|
||||
routerOptions?: FastifyRouterOptions<RawServer>,
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link FastifySchemaValidationError}
|
||||
*/
|
||||
export type ValidationResult = FastifySchemaValidationError;
|
||||
export type ValidationResult = FastifySchemaValidationError
|
||||
|
||||
/* Export additional types */
|
||||
export type {
|
||||
@@ -181,12 +191,12 @@ declare namespace fastify {
|
||||
FastifyRegister, FastifyRegisterOptions, RegisterOptions, // './types/register'
|
||||
FastifyBodyParser, FastifyContentTypeParser, AddContentTypeParser, hasContentTypeParser, getDefaultJsonParser, ProtoAction, ConstructorAction, // './types/content-type-parser'
|
||||
FastifyError, // '@fastify/error'
|
||||
FastifySchema, FastifySchemaCompiler, // './types/schema'
|
||||
FastifySchema, FastifySchemaValidationError, FastifySchemaCompiler, FastifySerializerCompiler, // './types/schema'
|
||||
HTTPMethods, RawServerBase, RawRequestDefaultExpression, RawReplyDefaultExpression, RawServerDefault, ContextConfigDefault, RequestBodyDefault, RequestQuerystringDefault, RequestParamsDefault, RequestHeadersDefault, // './types/utils'
|
||||
DoneFuncWithErrOrRes, HookHandlerDoneFunction, RequestPayload, onCloseAsyncHookHandler, onCloseHookHandler, onErrorAsyncHookHandler, onErrorHookHandler, onReadyAsyncHookHandler, onReadyHookHandler, onListenAsyncHookHandler, onListenHookHandler, onRegisterHookHandler, onRequestAsyncHookHandler, onRequestHookHandler, onResponseAsyncHookHandler, onResponseHookHandler, onRouteHookHandler, onSendAsyncHookHandler, onSendHookHandler, onTimeoutAsyncHookHandler, onTimeoutHookHandler, preHandlerAsyncHookHandler, preHandlerHookHandler, preParsingAsyncHookHandler, preParsingHookHandler, preSerializationAsyncHookHandler, preSerializationHookHandler, preValidationAsyncHookHandler, preValidationHookHandler, onRequestAbortHookHandler, onRequestAbortAsyncHookHandler, preCloseAsyncHookHandler, preCloseHookHandler, // './types/hooks'
|
||||
FastifyServerFactory, FastifyServerFactoryHandler, // './types/serverFactory'
|
||||
FastifyTypeProvider, FastifyTypeProviderDefault, // './types/type-provider'
|
||||
FastifyErrorCodes, // './types/errors'
|
||||
FastifyTypeProvider, FastifyTypeProviderDefault, SafePromiseLike, // './types/type-provider'
|
||||
FastifyErrorCodes // './types/errors'
|
||||
}
|
||||
// named export
|
||||
// import { plugin } from 'plugin'
|
||||
@@ -210,32 +220,32 @@ declare function fastify<
|
||||
Request extends RawRequestDefaultExpression<Server> = RawRequestDefaultExpression<Server>,
|
||||
Reply extends RawReplyDefaultExpression<Server> = RawReplyDefaultExpression<Server>,
|
||||
Logger extends FastifyBaseLogger = FastifyBaseLogger,
|
||||
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
|
||||
>(opts: fastify.FastifyHttp2SecureOptions<Server, Logger>): FastifyInstance<Server, Request, Reply, Logger, TypeProvider> & PromiseLike<FastifyInstance<Server, Request, Reply, Logger, TypeProvider>>
|
||||
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault
|
||||
> (opts: fastify.FastifyHttp2SecureOptions<Server, Logger>): FastifyInstance<Server, Request, Reply, Logger, TypeProvider> & SafePromiseLike<FastifyInstance<Server, Request, Reply, Logger, TypeProvider>>
|
||||
|
||||
declare function fastify<
|
||||
Server extends http2.Http2Server,
|
||||
Request extends RawRequestDefaultExpression<Server> = RawRequestDefaultExpression<Server>,
|
||||
Reply extends RawReplyDefaultExpression<Server> = RawReplyDefaultExpression<Server>,
|
||||
Logger extends FastifyBaseLogger = FastifyBaseLogger,
|
||||
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
|
||||
>(opts: fastify.FastifyHttp2Options<Server, Logger>): FastifyInstance<Server, Request, Reply, Logger, TypeProvider> & PromiseLike<FastifyInstance<Server, Request, Reply, Logger, TypeProvider>>
|
||||
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault
|
||||
> (opts: fastify.FastifyHttp2Options<Server, Logger>): FastifyInstance<Server, Request, Reply, Logger, TypeProvider> & SafePromiseLike<FastifyInstance<Server, Request, Reply, Logger, TypeProvider>>
|
||||
|
||||
declare function fastify<
|
||||
Server extends https.Server,
|
||||
Request extends RawRequestDefaultExpression<Server> = RawRequestDefaultExpression<Server>,
|
||||
Reply extends RawReplyDefaultExpression<Server> = RawReplyDefaultExpression<Server>,
|
||||
Logger extends FastifyBaseLogger = FastifyBaseLogger,
|
||||
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
|
||||
>(opts: fastify.FastifyHttpsOptions<Server, Logger>): FastifyInstance<Server, Request, Reply, Logger, TypeProvider> & PromiseLike<FastifyInstance<Server, Request, Reply, Logger, TypeProvider>>
|
||||
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault
|
||||
> (opts: fastify.FastifyHttpsOptions<Server, Logger>): FastifyInstance<Server, Request, Reply, Logger, TypeProvider> & SafePromiseLike<FastifyInstance<Server, Request, Reply, Logger, TypeProvider>>
|
||||
|
||||
declare function fastify<
|
||||
Server extends http.Server,
|
||||
Request extends RawRequestDefaultExpression<Server> = RawRequestDefaultExpression<Server>,
|
||||
Reply extends RawReplyDefaultExpression<Server> = RawReplyDefaultExpression<Server>,
|
||||
Logger extends FastifyBaseLogger = FastifyBaseLogger,
|
||||
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
|
||||
>(opts?: fastify.FastifyHttpOptions<Server, Logger>): FastifyInstance<Server, Request, Reply, Logger, TypeProvider> & PromiseLike<FastifyInstance<Server, Request, Reply, Logger, TypeProvider>>
|
||||
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault
|
||||
> (opts?: fastify.FastifyHttpOptions<Server, Logger>): FastifyInstance<Server, Request, Reply, Logger, TypeProvider> & SafePromiseLike<FastifyInstance<Server, Request, Reply, Logger, TypeProvider>>
|
||||
|
||||
// CJS export
|
||||
// const fastify = require('fastify')
|
||||
|
||||
519
backend/node_modules/fastify/fastify.js
generated
vendored
519
backend/node_modules/fastify/fastify.js
generated
vendored
@@ -1,9 +1,10 @@
|
||||
'use strict'
|
||||
|
||||
const VERSION = '4.29.1'
|
||||
const VERSION = '5.7.1'
|
||||
|
||||
const Avvio = require('avvio')
|
||||
const http = require('node:http')
|
||||
const diagnostics = require('node:diagnostics_channel')
|
||||
let lightMyRequest
|
||||
|
||||
const {
|
||||
@@ -11,6 +12,7 @@ const {
|
||||
kChildren,
|
||||
kServerBindings,
|
||||
kBodyLimit,
|
||||
kSupportedHTTPMethods,
|
||||
kRoutePrefix,
|
||||
kLogLevel,
|
||||
kLogSerializers,
|
||||
@@ -29,163 +31,70 @@ const {
|
||||
kErrorHandler,
|
||||
kKeepAliveConnections,
|
||||
kChildLoggerFactory,
|
||||
kGenReqId
|
||||
kGenReqId,
|
||||
kErrorHandlerAlreadySet
|
||||
} = require('./lib/symbols.js')
|
||||
|
||||
const { createServer, compileValidateHTTPVersion } = require('./lib/server')
|
||||
const { createServer } = require('./lib/server')
|
||||
const Reply = require('./lib/reply')
|
||||
const Request = require('./lib/request')
|
||||
const Context = require('./lib/context.js')
|
||||
const { supportedMethods } = require('./lib/httpMethods')
|
||||
const decorator = require('./lib/decorate')
|
||||
const ContentTypeParser = require('./lib/contentTypeParser')
|
||||
const ContentTypeParser = require('./lib/content-type-parser.js')
|
||||
const SchemaController = require('./lib/schema-controller')
|
||||
const { Hooks, hookRunnerApplication, supportedHooks } = require('./lib/hooks')
|
||||
const { createLogger, createChildLogger, defaultChildLoggerFactory } = require('./lib/logger')
|
||||
const pluginUtils = require('./lib/pluginUtils')
|
||||
const { getGenReqId, reqIdGenFactory } = require('./lib/reqIdGenFactory')
|
||||
const { buildRouting, validateBodyLimitOption } = require('./lib/route')
|
||||
const build404 = require('./lib/fourOhFour')
|
||||
const getSecuredInitialConfig = require('./lib/initialConfigValidation')
|
||||
const override = require('./lib/pluginOverride')
|
||||
const { FSTDEP009 } = require('./lib/warnings')
|
||||
const noopSet = require('./lib/noop-set')
|
||||
const { createChildLogger, defaultChildLoggerFactory, createLogger } = require('./lib/logger-factory')
|
||||
const pluginUtils = require('./lib/plugin-utils.js')
|
||||
const { getGenReqId, reqIdGenFactory } = require('./lib/req-id-gen-factory.js')
|
||||
const { buildRouting, validateBodyLimitOption, buildRouterOptions } = require('./lib/route')
|
||||
const build404 = require('./lib/four-oh-four')
|
||||
const getSecuredInitialConfig = require('./lib/initial-config-validation.js')
|
||||
const override = require('./lib/plugin-override')
|
||||
const {
|
||||
appendStackTrace,
|
||||
AVVIO_ERRORS_MAP,
|
||||
...errorCodes
|
||||
} = require('./lib/errors')
|
||||
const PonyPromise = require('./lib/promise')
|
||||
|
||||
const { defaultInitOptions } = getSecuredInitialConfig
|
||||
|
||||
const {
|
||||
FST_ERR_ASYNC_CONSTRAINT,
|
||||
FST_ERR_BAD_URL,
|
||||
FST_ERR_FORCE_CLOSE_CONNECTIONS_IDLE_NOT_AVAILABLE,
|
||||
FST_ERR_OPTIONS_NOT_OBJ,
|
||||
FST_ERR_QSP_NOT_FN,
|
||||
FST_ERR_SCHEMA_CONTROLLER_BUCKET_OPT_NOT_FN,
|
||||
FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_OBJ,
|
||||
FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_ARR,
|
||||
FST_ERR_VERSION_CONSTRAINT_NOT_STR,
|
||||
FST_ERR_INSTANCE_ALREADY_LISTENING,
|
||||
FST_ERR_REOPENED_CLOSE_SERVER,
|
||||
FST_ERR_ROUTE_REWRITE_NOT_STR,
|
||||
FST_ERR_SCHEMA_ERROR_FORMATTER_NOT_FN,
|
||||
FST_ERR_ERROR_HANDLER_NOT_FN
|
||||
FST_ERR_ERROR_HANDLER_NOT_FN,
|
||||
FST_ERR_ERROR_HANDLER_ALREADY_SET,
|
||||
FST_ERR_ROUTE_METHOD_INVALID
|
||||
} = errorCodes
|
||||
|
||||
const { buildErrorHandler } = require('./lib/error-handler.js')
|
||||
const { FSTWRN004 } = require('./lib/warnings.js')
|
||||
|
||||
function defaultBuildPrettyMeta (route) {
|
||||
// return a shallow copy of route's sanitized context
|
||||
|
||||
const cleanKeys = {}
|
||||
const allowedProps = ['errorHandler', 'logLevel', 'logSerializers']
|
||||
|
||||
allowedProps.concat(supportedHooks).forEach(k => {
|
||||
cleanKeys[k] = route.store[k]
|
||||
})
|
||||
|
||||
return Object.assign({}, cleanKeys)
|
||||
}
|
||||
const initChannel = diagnostics.channel('fastify.initialization')
|
||||
|
||||
/**
|
||||
* @param {import('./fastify.js').FastifyServerOptions} options
|
||||
* @param {import('./fastify.js').FastifyServerOptions} serverOptions
|
||||
*/
|
||||
function fastify (options) {
|
||||
// Options validations
|
||||
options = options || {}
|
||||
|
||||
if (typeof options !== 'object') {
|
||||
throw new FST_ERR_OPTIONS_NOT_OBJ()
|
||||
}
|
||||
|
||||
if (options.querystringParser && typeof options.querystringParser !== 'function') {
|
||||
throw new FST_ERR_QSP_NOT_FN(typeof options.querystringParser)
|
||||
}
|
||||
|
||||
if (options.schemaController && options.schemaController.bucket && typeof options.schemaController.bucket !== 'function') {
|
||||
throw new FST_ERR_SCHEMA_CONTROLLER_BUCKET_OPT_NOT_FN(typeof options.schemaController.bucket)
|
||||
}
|
||||
|
||||
validateBodyLimitOption(options.bodyLimit)
|
||||
|
||||
const requestIdHeader = (options.requestIdHeader === false) ? false : (options.requestIdHeader || defaultInitOptions.requestIdHeader).toLowerCase()
|
||||
const genReqId = reqIdGenFactory(requestIdHeader, options.genReqId)
|
||||
const requestIdLogLabel = options.requestIdLogLabel || 'reqId'
|
||||
const bodyLimit = options.bodyLimit || defaultInitOptions.bodyLimit
|
||||
const disableRequestLogging = options.disableRequestLogging || false
|
||||
|
||||
const ajvOptions = Object.assign({
|
||||
customOptions: {},
|
||||
plugins: []
|
||||
}, options.ajv)
|
||||
const frameworkErrors = options.frameworkErrors
|
||||
|
||||
// Ajv options
|
||||
if (!ajvOptions.customOptions || Object.prototype.toString.call(ajvOptions.customOptions) !== '[object Object]') {
|
||||
throw new FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_OBJ(typeof ajvOptions.customOptions)
|
||||
}
|
||||
if (!ajvOptions.plugins || !Array.isArray(ajvOptions.plugins)) {
|
||||
throw new FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_ARR(typeof ajvOptions.plugins)
|
||||
}
|
||||
|
||||
// Instance Fastify components
|
||||
const { logger, hasLogger } = createLogger(options)
|
||||
|
||||
// Update the options with the fixed values
|
||||
options.connectionTimeout = options.connectionTimeout || defaultInitOptions.connectionTimeout
|
||||
options.keepAliveTimeout = options.keepAliveTimeout || defaultInitOptions.keepAliveTimeout
|
||||
options.maxRequestsPerSocket = options.maxRequestsPerSocket || defaultInitOptions.maxRequestsPerSocket
|
||||
options.requestTimeout = options.requestTimeout || defaultInitOptions.requestTimeout
|
||||
options.logger = logger
|
||||
options.requestIdHeader = requestIdHeader
|
||||
options.requestIdLogLabel = requestIdLogLabel
|
||||
options.disableRequestLogging = disableRequestLogging
|
||||
options.ajv = ajvOptions
|
||||
options.clientErrorHandler = options.clientErrorHandler || defaultClientErrorHandler
|
||||
|
||||
const initialConfig = getSecuredInitialConfig(options)
|
||||
|
||||
// exposeHeadRoutes have its default set from the validator
|
||||
options.exposeHeadRoutes = initialConfig.exposeHeadRoutes
|
||||
|
||||
let constraints = options.constraints
|
||||
if (options.versioning) {
|
||||
FSTDEP009()
|
||||
constraints = {
|
||||
...constraints,
|
||||
version: {
|
||||
name: 'version',
|
||||
mustMatchWhenDerived: true,
|
||||
storage: options.versioning.storage,
|
||||
deriveConstraint: options.versioning.deriveVersion,
|
||||
validate (value) {
|
||||
if (typeof value !== 'string') {
|
||||
throw new FST_ERR_VERSION_CONSTRAINT_NOT_STR()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function fastify (serverOptions) {
|
||||
const {
|
||||
options,
|
||||
genReqId,
|
||||
disableRequestLogging,
|
||||
hasLogger,
|
||||
initialConfig
|
||||
} = processOptions(serverOptions, defaultRoute, onBadUrl)
|
||||
|
||||
// Default router
|
||||
const router = buildRouting({
|
||||
config: {
|
||||
defaultRoute,
|
||||
onBadUrl,
|
||||
constraints,
|
||||
ignoreTrailingSlash: options.ignoreTrailingSlash || defaultInitOptions.ignoreTrailingSlash,
|
||||
ignoreDuplicateSlashes: options.ignoreDuplicateSlashes || defaultInitOptions.ignoreDuplicateSlashes,
|
||||
maxParamLength: options.maxParamLength || defaultInitOptions.maxParamLength,
|
||||
caseSensitive: options.caseSensitive,
|
||||
allowUnsafeRegex: options.allowUnsafeRegex || defaultInitOptions.allowUnsafeRegex,
|
||||
buildPrettyMeta: defaultBuildPrettyMeta,
|
||||
querystringParser: options.querystringParser,
|
||||
useSemicolonDelimiter: options.useSemicolonDelimiter ?? defaultInitOptions.useSemicolonDelimiter
|
||||
}
|
||||
})
|
||||
const router = buildRouting(options.routerOptions)
|
||||
|
||||
// 404 router, used for handling encapsulated 404 handlers
|
||||
const fourOhFour = build404(options)
|
||||
@@ -193,22 +102,14 @@ function fastify (options) {
|
||||
// HTTP server and its handler
|
||||
const httpHandler = wrapRouting(router, options)
|
||||
|
||||
// we need to set this before calling createServer
|
||||
options.http2SessionTimeout = initialConfig.http2SessionTimeout
|
||||
const { server, listen } = createServer(options, httpHandler)
|
||||
|
||||
const serverHasCloseAllConnections = typeof server.closeAllConnections === 'function'
|
||||
const serverHasCloseIdleConnections = typeof server.closeIdleConnections === 'function'
|
||||
|
||||
let forceCloseConnections = options.forceCloseConnections
|
||||
if (forceCloseConnections === 'idle' && !serverHasCloseIdleConnections) {
|
||||
throw new FST_ERR_FORCE_CLOSE_CONNECTIONS_IDLE_NOT_AVAILABLE()
|
||||
} else if (typeof forceCloseConnections !== 'boolean') {
|
||||
/* istanbul ignore next: only one branch can be valid in a given Node.js version */
|
||||
forceCloseConnections = serverHasCloseIdleConnections ? 'idle' : false
|
||||
}
|
||||
|
||||
const keepAliveConnections = !serverHasCloseAllConnections && forceCloseConnections === true ? new Set() : noopSet()
|
||||
const {
|
||||
server,
|
||||
listen,
|
||||
forceCloseConnections,
|
||||
serverHasCloseAllConnections,
|
||||
serverHasCloseHttp2Sessions,
|
||||
keepAliveConnections
|
||||
} = createServer(options, httpHandler)
|
||||
|
||||
const setupResponseListeners = Reply.setupResponseListeners
|
||||
const schemaController = SchemaController.buildSchemaController(null, options.schemaController)
|
||||
@@ -222,13 +123,30 @@ function fastify (options) {
|
||||
started: false,
|
||||
ready: false,
|
||||
booting: false,
|
||||
readyPromise: null
|
||||
aborted: false,
|
||||
readyResolver: null
|
||||
},
|
||||
[kKeepAliveConnections]: keepAliveConnections,
|
||||
[kSupportedHTTPMethods]: {
|
||||
bodyless: new Set([
|
||||
// Standard
|
||||
'GET',
|
||||
'HEAD',
|
||||
'TRACE'
|
||||
]),
|
||||
bodywith: new Set([
|
||||
// Standard
|
||||
'DELETE',
|
||||
'OPTIONS',
|
||||
'PATCH',
|
||||
'PUT',
|
||||
'POST'
|
||||
])
|
||||
},
|
||||
[kOptions]: options,
|
||||
[kChildren]: [],
|
||||
[kServerBindings]: [],
|
||||
[kBodyLimit]: bodyLimit,
|
||||
[kBodyLimit]: options.bodyLimit,
|
||||
[kRoutePrefix]: '',
|
||||
[kLogLevel]: '',
|
||||
[kLogSerializers]: null,
|
||||
@@ -236,10 +154,11 @@ function fastify (options) {
|
||||
[kSchemaController]: schemaController,
|
||||
[kSchemaErrorFormatter]: null,
|
||||
[kErrorHandler]: buildErrorHandler(),
|
||||
[kChildLoggerFactory]: defaultChildLoggerFactory,
|
||||
[kErrorHandlerAlreadySet]: false,
|
||||
[kChildLoggerFactory]: options.childLoggerFactory || defaultChildLoggerFactory,
|
||||
[kReplySerializerDefault]: null,
|
||||
[kContentTypeParser]: new ContentTypeParser(
|
||||
bodyLimit,
|
||||
options.bodyLimit,
|
||||
(options.onProtoPoisoning || defaultInitOptions.onProtoPoisoning),
|
||||
(options.onConstructorPoisoning || defaultInitOptions.onConstructorPoisoning)
|
||||
),
|
||||
@@ -252,8 +171,6 @@ function fastify (options) {
|
||||
[kGenReqId]: genReqId,
|
||||
// routing method
|
||||
routing: httpHandler,
|
||||
getDefaultRoute: router.getDefaultRoute.bind(router),
|
||||
setDefaultRoute: router.setDefaultRoute.bind(router),
|
||||
// routes shorthand methods
|
||||
delete: function _delete (url, options, handler) {
|
||||
return router.prepareRoute.call(this, { method: 'DELETE', url, options, handler })
|
||||
@@ -264,6 +181,9 @@ function fastify (options) {
|
||||
head: function _head (url, options, handler) {
|
||||
return router.prepareRoute.call(this, { method: 'HEAD', url, options, handler })
|
||||
},
|
||||
trace: function _trace (url, options, handler) {
|
||||
return router.prepareRoute.call(this, { method: 'TRACE', url, options, handler })
|
||||
},
|
||||
patch: function _patch (url, options, handler) {
|
||||
return router.prepareRoute.call(this, { method: 'PATCH', url, options, handler })
|
||||
},
|
||||
@@ -277,7 +197,7 @@ function fastify (options) {
|
||||
return router.prepareRoute.call(this, { method: 'OPTIONS', url, options, handler })
|
||||
},
|
||||
all: function _all (url, options, handler) {
|
||||
return router.prepareRoute.call(this, { method: supportedMethods, url, options, handler })
|
||||
return router.prepareRoute.call(this, { method: this.supportedMethods, url, options, handler })
|
||||
},
|
||||
// extended route
|
||||
route: function _route (options) {
|
||||
@@ -292,7 +212,7 @@ function fastify (options) {
|
||||
return router.findRoute(options)
|
||||
},
|
||||
// expose logger instance
|
||||
log: logger,
|
||||
log: options.logger,
|
||||
// type provider
|
||||
withTypeProvider,
|
||||
// hooks
|
||||
@@ -341,6 +261,8 @@ function fastify (options) {
|
||||
decorateRequest: decorator.decorateRequest,
|
||||
hasRequestDecorator: decorator.existRequest,
|
||||
hasReplyDecorator: decorator.existReply,
|
||||
getDecorator: decorator.getInstanceDecorator,
|
||||
addHttpMethod,
|
||||
// fake http injection
|
||||
inject,
|
||||
// pretty print of the registered routes
|
||||
@@ -408,6 +330,15 @@ function fastify (options) {
|
||||
genReqId: {
|
||||
configurable: true,
|
||||
get () { return this[kGenReqId] }
|
||||
},
|
||||
supportedMethods: {
|
||||
configurable: false,
|
||||
get () {
|
||||
return [
|
||||
...this[kSupportedHTTPMethods].bodyless,
|
||||
...this[kSupportedHTTPMethods].bodywith
|
||||
]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -451,7 +382,7 @@ function fastify (options) {
|
||||
if (forceCloseConnections === 'idle') {
|
||||
// Not needed in Node 19
|
||||
instance.server.closeIdleConnections()
|
||||
/* istanbul ignore next: Cannot test this without Node.js core support */
|
||||
/* istanbul ignore next: Cannot test this without Node.js core support */
|
||||
} else if (serverHasCloseAllConnections && forceCloseConnections) {
|
||||
instance.server.closeAllConnections()
|
||||
} else if (forceCloseConnections === true) {
|
||||
@@ -466,6 +397,10 @@ function fastify (options) {
|
||||
}
|
||||
}
|
||||
|
||||
if (serverHasCloseHttp2Sessions) {
|
||||
instance.server.closeHttp2Sessions()
|
||||
}
|
||||
|
||||
// No new TCP connections are accepted.
|
||||
// We must call close on the server even if we are not listening
|
||||
// otherwise memory will be leaked.
|
||||
@@ -499,26 +434,17 @@ function fastify (options) {
|
||||
router.setup(options, {
|
||||
avvio,
|
||||
fourOhFour,
|
||||
logger,
|
||||
hasLogger,
|
||||
setupResponseListeners,
|
||||
throwIfAlreadyStarted,
|
||||
validateHTTPVersion: compileValidateHTTPVersion(options),
|
||||
keepAliveConnections
|
||||
})
|
||||
|
||||
// Delay configuring clientError handler so that it can access fastify state.
|
||||
server.on('clientError', options.clientErrorHandler.bind(fastify))
|
||||
|
||||
try {
|
||||
const dc = require('node:diagnostics_channel')
|
||||
const initChannel = dc.channel('fastify.initialization')
|
||||
if (initChannel.hasSubscribers) {
|
||||
initChannel.publish({ fastify })
|
||||
}
|
||||
} catch (e) {
|
||||
// This only happens if `diagnostics_channel` isn't available, i.e. earlier
|
||||
// versions of Node.js. In that event, we don't care, so ignore the error.
|
||||
if (initChannel.hasSubscribers) {
|
||||
initChannel.publish({ fastify })
|
||||
}
|
||||
|
||||
// Older nodejs versions may not have asyncDispose
|
||||
@@ -577,18 +503,15 @@ function fastify (options) {
|
||||
}
|
||||
|
||||
function ready (cb) {
|
||||
if (this[kState].readyPromise !== null) {
|
||||
if (this[kState].readyResolver !== null) {
|
||||
if (cb != null) {
|
||||
this[kState].readyPromise.then(() => cb(null, fastify), cb)
|
||||
this[kState].readyResolver.promise.then(() => cb(null, fastify), cb)
|
||||
return
|
||||
}
|
||||
|
||||
return this[kState].readyPromise
|
||||
return this[kState].readyResolver.promise
|
||||
}
|
||||
|
||||
let resolveReady
|
||||
let rejectReady
|
||||
|
||||
// run the hooks after returning the promise
|
||||
process.nextTick(runHooks)
|
||||
|
||||
@@ -596,15 +519,12 @@ function fastify (options) {
|
||||
// It will work as a barrier for all the .ready() calls (ensuring single hook execution)
|
||||
// as well as a flow control mechanism to chain cbs and further
|
||||
// promises
|
||||
this[kState].readyPromise = new Promise(function (resolve, reject) {
|
||||
resolveReady = resolve
|
||||
rejectReady = reject
|
||||
})
|
||||
this[kState].readyResolver = PonyPromise.withResolvers()
|
||||
|
||||
if (!cb) {
|
||||
return this[kState].readyPromise
|
||||
return this[kState].readyResolver.promise
|
||||
} else {
|
||||
this[kState].readyPromise.then(() => cb(null, fastify), cb)
|
||||
this[kState].readyResolver.promise.then(() => cb(null, fastify), cb)
|
||||
}
|
||||
|
||||
function runHooks () {
|
||||
@@ -629,13 +549,13 @@ function fastify (options) {
|
||||
: err
|
||||
|
||||
if (err) {
|
||||
return rejectReady(err)
|
||||
return fastify[kState].readyResolver.reject(err)
|
||||
}
|
||||
|
||||
resolveReady(fastify)
|
||||
fastify[kState].readyResolver.resolve(fastify)
|
||||
fastify[kState].booting = false
|
||||
fastify[kState].ready = true
|
||||
fastify[kState].promise = null
|
||||
fastify[kState].readyResolver = null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -676,8 +596,12 @@ function fastify (options) {
|
||||
this[kHooks].add(name, fn)
|
||||
} else {
|
||||
this.after((err, done) => {
|
||||
_addHook.call(this, name, fn)
|
||||
done(err)
|
||||
try {
|
||||
_addHook.call(this, name, fn)
|
||||
done(err)
|
||||
} catch (err) {
|
||||
done(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
return this
|
||||
@@ -696,46 +620,6 @@ function fastify (options) {
|
||||
return this
|
||||
}
|
||||
|
||||
function defaultClientErrorHandler (err, socket) {
|
||||
// In case of a connection reset, the socket has been destroyed and there is nothing that needs to be done.
|
||||
// https://nodejs.org/api/http.html#http_event_clienterror
|
||||
if (err.code === 'ECONNRESET' || socket.destroyed) {
|
||||
return
|
||||
}
|
||||
|
||||
let body, errorCode, errorStatus, errorLabel
|
||||
|
||||
if (err.code === 'ERR_HTTP_REQUEST_TIMEOUT') {
|
||||
errorCode = '408'
|
||||
errorStatus = http.STATUS_CODES[errorCode]
|
||||
body = `{"error":"${errorStatus}","message":"Client Timeout","statusCode":408}`
|
||||
errorLabel = 'timeout'
|
||||
} else if (err.code === 'HPE_HEADER_OVERFLOW') {
|
||||
errorCode = '431'
|
||||
errorStatus = http.STATUS_CODES[errorCode]
|
||||
body = `{"error":"${errorStatus}","message":"Exceeded maximum allowed HTTP header size","statusCode":431}`
|
||||
errorLabel = 'header_overflow'
|
||||
} else {
|
||||
errorCode = '400'
|
||||
errorStatus = http.STATUS_CODES[errorCode]
|
||||
body = `{"error":"${errorStatus}","message":"Client Error","statusCode":400}`
|
||||
errorLabel = 'error'
|
||||
}
|
||||
|
||||
// Most devs do not know what to do with this error.
|
||||
// In the vast majority of cases, it's a network error and/or some
|
||||
// config issue on the load balancer side.
|
||||
this.log.trace({ err }, `client ${errorLabel}`)
|
||||
// Copying standard node behavior
|
||||
// https://github.com/nodejs/node/blob/6ca23d7846cb47e84fd344543e394e50938540be/lib/_http_server.js#L666
|
||||
|
||||
// If the socket is not writable, there is no reason to try to send data.
|
||||
if (socket.writable) {
|
||||
socket.write(`HTTP/1.1 ${errorCode} ${errorStatus}\r\nContent-Length: ${body.length}\r\nContent-Type: application/json\r\n\r\n${body}`)
|
||||
}
|
||||
socket.destroy(err)
|
||||
}
|
||||
|
||||
// If the router does not match any route, every request will land here
|
||||
// req and res are Node.js core objects
|
||||
function defaultRoute (req, res) {
|
||||
@@ -750,23 +634,29 @@ function fastify (options) {
|
||||
}
|
||||
|
||||
function onBadUrl (path, req, res) {
|
||||
if (frameworkErrors) {
|
||||
if (options.frameworkErrors) {
|
||||
const id = getGenReqId(onBadUrlContext.server, req)
|
||||
const childLogger = createChildLogger(onBadUrlContext, logger, req, id)
|
||||
const childLogger = createChildLogger(onBadUrlContext, options.logger, req, id)
|
||||
|
||||
const request = new Request(id, null, req, null, childLogger, onBadUrlContext)
|
||||
const reply = new Reply(res, request, childLogger)
|
||||
|
||||
if (disableRequestLogging === false) {
|
||||
const resolvedDisableRequestLogging = typeof disableRequestLogging === 'function' ? disableRequestLogging(req) : disableRequestLogging
|
||||
if (resolvedDisableRequestLogging === false) {
|
||||
childLogger.info({ req: request }, 'incoming request')
|
||||
}
|
||||
|
||||
return frameworkErrors(new FST_ERR_BAD_URL(path), request, reply)
|
||||
return options.frameworkErrors(new FST_ERR_BAD_URL(path), request, reply)
|
||||
}
|
||||
const body = `{"error":"Bad Request","code":"FST_ERR_BAD_URL","message":"'${path}' is not a valid url component","statusCode":400}`
|
||||
const body = JSON.stringify({
|
||||
error: 'Bad Request',
|
||||
code: 'FST_ERR_BAD_URL',
|
||||
message: `'${path}' is not a valid url component`,
|
||||
statusCode: 400
|
||||
})
|
||||
res.writeHead(400, {
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': body.length
|
||||
'Content-Length': Buffer.byteLength(body)
|
||||
})
|
||||
res.end(body)
|
||||
}
|
||||
@@ -775,18 +665,19 @@ function fastify (options) {
|
||||
if (isAsync === false) return undefined
|
||||
return function onAsyncConstraintError (err) {
|
||||
if (err) {
|
||||
if (frameworkErrors) {
|
||||
if (options.frameworkErrors) {
|
||||
const id = getGenReqId(onBadUrlContext.server, req)
|
||||
const childLogger = createChildLogger(onBadUrlContext, logger, req, id)
|
||||
const childLogger = createChildLogger(onBadUrlContext, options.logger, req, id)
|
||||
|
||||
const request = new Request(id, null, req, null, childLogger, onBadUrlContext)
|
||||
const reply = new Reply(res, request, childLogger)
|
||||
|
||||
if (disableRequestLogging === false) {
|
||||
const resolvedDisableRequestLogging = typeof disableRequestLogging === 'function' ? disableRequestLogging(req) : disableRequestLogging
|
||||
if (resolvedDisableRequestLogging === false) {
|
||||
childLogger.info({ req: request }, 'incoming request')
|
||||
}
|
||||
|
||||
return frameworkErrors(new FST_ERR_ASYNC_CONSTRAINT(), request, reply)
|
||||
return options.frameworkErrors(new FST_ERR_ASYNC_CONSTRAINT(), request, reply)
|
||||
}
|
||||
const body = '{"error":"Internal Server Error","message":"Unexpected error from async constraint","statusCode":500}'
|
||||
res.writeHead(500, {
|
||||
@@ -827,7 +718,10 @@ function fastify (options) {
|
||||
function setSchemaController (schemaControllerOpts) {
|
||||
throwIfAlreadyStarted('Cannot call "setSchemaController"!')
|
||||
const old = this[kSchemaController]
|
||||
const schemaController = SchemaController.buildSchemaController(old, Object.assign({}, old.opts, schemaControllerOpts))
|
||||
const schemaController = SchemaController.buildSchemaController(
|
||||
old,
|
||||
Object.assign({}, old.opts, schemaControllerOpts)
|
||||
)
|
||||
this[kSchemaController] = schemaController
|
||||
this.getSchema = schemaController.getSchema.bind(schemaController)
|
||||
this.getSchemas = schemaController.getSchemas.bind(schemaController)
|
||||
@@ -849,6 +743,13 @@ function fastify (options) {
|
||||
throw new FST_ERR_ERROR_HANDLER_NOT_FN()
|
||||
}
|
||||
|
||||
if (!options.allowErrorHandlerOverride && this[kErrorHandlerAlreadySet]) {
|
||||
throw new FST_ERR_ERROR_HANDLER_ALREADY_SET()
|
||||
} else if (this[kErrorHandlerAlreadySet]) {
|
||||
FSTWRN004("To disable this behavior, set 'allowErrorHandlerOverride' to false or ignore this message. For more information, visit: https://fastify.dev/docs/latest/Reference/Server/#allowerrorhandleroverride")
|
||||
}
|
||||
|
||||
this[kErrorHandlerAlreadySet] = true
|
||||
this[kErrorHandler] = buildErrorHandler(this[kErrorHandler], func.bind(this))
|
||||
return this
|
||||
}
|
||||
@@ -862,7 +763,9 @@ function fastify (options) {
|
||||
|
||||
function printRoutes (opts = {}) {
|
||||
// includeHooks:true - shortcut to include all supported hooks exported by fastify.Hooks
|
||||
opts.includeMeta = opts.includeHooks ? opts.includeMeta ? supportedHooks.concat(opts.includeMeta) : supportedHooks : opts.includeMeta
|
||||
opts.includeMeta = opts.includeHooks
|
||||
? opts.includeMeta ? supportedHooks.concat(opts.includeMeta) : supportedHooks
|
||||
: opts.includeMeta
|
||||
return router.printRoutes(opts)
|
||||
}
|
||||
|
||||
@@ -891,6 +794,168 @@ function fastify (options) {
|
||||
this[kGenReqId] = reqIdGenFactory(this[kOptions].requestIdHeader, func)
|
||||
return this
|
||||
}
|
||||
|
||||
function addHttpMethod (method, { hasBody = false } = {}) {
|
||||
if (typeof method !== 'string' || http.METHODS.indexOf(method) === -1) {
|
||||
throw new FST_ERR_ROUTE_METHOD_INVALID()
|
||||
}
|
||||
|
||||
if (hasBody === true) {
|
||||
this[kSupportedHTTPMethods].bodywith.add(method)
|
||||
this[kSupportedHTTPMethods].bodyless.delete(method)
|
||||
} else {
|
||||
this[kSupportedHTTPMethods].bodywith.delete(method)
|
||||
this[kSupportedHTTPMethods].bodyless.add(method)
|
||||
}
|
||||
|
||||
const _method = method.toLowerCase()
|
||||
if (!this.hasDecorator(_method)) {
|
||||
this.decorate(_method, function (url, options, handler) {
|
||||
return router.prepareRoute.call(this, { method, url, options, handler })
|
||||
})
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
function processOptions (options, defaultRoute, onBadUrl) {
|
||||
// Options validations
|
||||
if (options && typeof options !== 'object') {
|
||||
throw new FST_ERR_OPTIONS_NOT_OBJ()
|
||||
} else {
|
||||
// Shallow copy options object to prevent mutations outside of this function
|
||||
options = Object.assign({}, options)
|
||||
}
|
||||
|
||||
if (
|
||||
(options.querystringParser && typeof options.querystringParser !== 'function') ||
|
||||
(
|
||||
options.routerOptions?.querystringParser &&
|
||||
typeof options.routerOptions.querystringParser !== 'function'
|
||||
)
|
||||
) {
|
||||
throw new FST_ERR_QSP_NOT_FN(typeof (options.querystringParser ?? options.routerOptions.querystringParser))
|
||||
}
|
||||
|
||||
if (options.schemaController && options.schemaController.bucket && typeof options.schemaController.bucket !== 'function') {
|
||||
throw new FST_ERR_SCHEMA_CONTROLLER_BUCKET_OPT_NOT_FN(typeof options.schemaController.bucket)
|
||||
}
|
||||
|
||||
validateBodyLimitOption(options.bodyLimit)
|
||||
|
||||
const requestIdHeader = typeof options.requestIdHeader === 'string' && options.requestIdHeader.length !== 0 ? options.requestIdHeader.toLowerCase() : (options.requestIdHeader === true && 'request-id')
|
||||
const genReqId = reqIdGenFactory(requestIdHeader, options.genReqId)
|
||||
const requestIdLogLabel = options.requestIdLogLabel || 'reqId'
|
||||
options.bodyLimit = options.bodyLimit || defaultInitOptions.bodyLimit
|
||||
const disableRequestLogging = options.disableRequestLogging || false
|
||||
|
||||
const ajvOptions = Object.assign({
|
||||
customOptions: {},
|
||||
plugins: []
|
||||
}, options.ajv)
|
||||
|
||||
if (!ajvOptions.customOptions || Object.prototype.toString.call(ajvOptions.customOptions) !== '[object Object]') {
|
||||
throw new FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_OBJ(typeof ajvOptions.customOptions)
|
||||
}
|
||||
if (!ajvOptions.plugins || !Array.isArray(ajvOptions.plugins)) {
|
||||
throw new FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_ARR(typeof ajvOptions.plugins)
|
||||
}
|
||||
|
||||
const { logger, hasLogger } = createLogger(options)
|
||||
|
||||
// Update the options with the fixed values
|
||||
options.connectionTimeout = options.connectionTimeout || defaultInitOptions.connectionTimeout
|
||||
options.keepAliveTimeout = options.keepAliveTimeout || defaultInitOptions.keepAliveTimeout
|
||||
options.maxRequestsPerSocket = options.maxRequestsPerSocket || defaultInitOptions.maxRequestsPerSocket
|
||||
options.requestTimeout = options.requestTimeout || defaultInitOptions.requestTimeout
|
||||
options.logger = logger
|
||||
options.requestIdHeader = requestIdHeader
|
||||
options.requestIdLogLabel = requestIdLogLabel
|
||||
options.disableRequestLogging = disableRequestLogging
|
||||
options.ajv = ajvOptions
|
||||
options.clientErrorHandler = options.clientErrorHandler || defaultClientErrorHandler
|
||||
options.allowErrorHandlerOverride = options.allowErrorHandlerOverride ?? defaultInitOptions.allowErrorHandlerOverride
|
||||
|
||||
const initialConfig = getSecuredInitialConfig(options)
|
||||
|
||||
// exposeHeadRoutes have its default set from the validator
|
||||
options.exposeHeadRoutes = initialConfig.exposeHeadRoutes
|
||||
|
||||
// we need to set this before calling createServer
|
||||
options.http2SessionTimeout = initialConfig.http2SessionTimeout
|
||||
|
||||
options.routerOptions = buildRouterOptions(options, {
|
||||
defaultRoute,
|
||||
onBadUrl,
|
||||
ignoreTrailingSlash: defaultInitOptions.ignoreTrailingSlash,
|
||||
ignoreDuplicateSlashes: defaultInitOptions.ignoreDuplicateSlashes,
|
||||
maxParamLength: defaultInitOptions.maxParamLength,
|
||||
allowUnsafeRegex: defaultInitOptions.allowUnsafeRegex,
|
||||
buildPrettyMeta: defaultBuildPrettyMeta,
|
||||
useSemicolonDelimiter: defaultInitOptions.useSemicolonDelimiter
|
||||
})
|
||||
|
||||
return {
|
||||
options,
|
||||
genReqId,
|
||||
disableRequestLogging,
|
||||
hasLogger,
|
||||
initialConfig
|
||||
}
|
||||
}
|
||||
|
||||
function defaultBuildPrettyMeta (route) {
|
||||
// return a shallow copy of route's sanitized context
|
||||
|
||||
const cleanKeys = {}
|
||||
const allowedProps = ['errorHandler', 'logLevel', 'logSerializers']
|
||||
|
||||
allowedProps.concat(supportedHooks).forEach(k => {
|
||||
cleanKeys[k] = route.store[k]
|
||||
})
|
||||
|
||||
return Object.assign({}, cleanKeys)
|
||||
}
|
||||
|
||||
function defaultClientErrorHandler (err, socket) {
|
||||
// In case of a connection reset, the socket has been destroyed and there is nothing that needs to be done.
|
||||
// https://nodejs.org/api/http.html#http_event_clienterror
|
||||
if (err.code === 'ECONNRESET' || socket.destroyed) {
|
||||
return
|
||||
}
|
||||
|
||||
let body, errorCode, errorStatus, errorLabel
|
||||
|
||||
if (err.code === 'ERR_HTTP_REQUEST_TIMEOUT') {
|
||||
errorCode = '408'
|
||||
errorStatus = http.STATUS_CODES[errorCode]
|
||||
body = `{"error":"${errorStatus}","message":"Client Timeout","statusCode":408}`
|
||||
errorLabel = 'timeout'
|
||||
} else if (err.code === 'HPE_HEADER_OVERFLOW') {
|
||||
errorCode = '431'
|
||||
errorStatus = http.STATUS_CODES[errorCode]
|
||||
body = `{"error":"${errorStatus}","message":"Exceeded maximum allowed HTTP header size","statusCode":431}`
|
||||
errorLabel = 'header_overflow'
|
||||
} else {
|
||||
errorCode = '400'
|
||||
errorStatus = http.STATUS_CODES[errorCode]
|
||||
body = `{"error":"${errorStatus}","message":"Client Error","statusCode":400}`
|
||||
errorLabel = 'error'
|
||||
}
|
||||
|
||||
// Most devs do not know what to do with this error.
|
||||
// In the vast majority of cases, it's a network error and/or some
|
||||
// config issue on the load balancer side.
|
||||
this.log.trace({ err }, `client ${errorLabel}`)
|
||||
// Copying standard node behavior
|
||||
// https://github.com/nodejs/node/blob/6ca23d7846cb47e84fd344543e394e50938540be/lib/_http_server.js#L666
|
||||
|
||||
// If the socket is not writable, there is no reason to try to send data.
|
||||
if (socket.writable) {
|
||||
socket.write(`HTTP/1.1 ${errorCode} ${errorStatus}\r\nContent-Length: ${body.length}\r\nContent-Type: application/json\r\n\r\n${body}`)
|
||||
}
|
||||
socket.destroy(err)
|
||||
}
|
||||
|
||||
function validateSchemaErrorFormatter (schemaErrorFormatter) {
|
||||
@@ -903,7 +968,7 @@ function validateSchemaErrorFormatter (schemaErrorFormatter) {
|
||||
|
||||
/**
|
||||
* These export configurations enable JS and TS developers
|
||||
* to consumer fastify in whatever way best suits their needs.
|
||||
* to consume fastify in whatever way best suits their needs.
|
||||
* Some examples of supported import syntax includes:
|
||||
* - `const fastify = require('fastify')`
|
||||
* - `const { fastify } = require('fastify')`
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// This file is autogenerated by build/build-validation.js, do not edit
|
||||
/* istanbul ignore file */
|
||||
/* c8 ignore start */
|
||||
"use strict";
|
||||
module.exports = validate10;
|
||||
module.exports.default = validate10;
|
||||
const schema11 = {"type":"object","additionalProperties":false,"properties":{"connectionTimeout":{"type":"integer","default":0},"keepAliveTimeout":{"type":"integer","default":72000},"forceCloseConnections":{"oneOf":[{"type":"string","pattern":"idle"},{"type":"boolean"}]},"maxRequestsPerSocket":{"type":"integer","default":0,"nullable":true},"requestTimeout":{"type":"integer","default":0},"bodyLimit":{"type":"integer","default":1048576},"caseSensitive":{"type":"boolean","default":true},"allowUnsafeRegex":{"type":"boolean","default":false},"http2":{"type":"boolean"},"https":{"if":{"not":{"oneOf":[{"type":"boolean"},{"type":"null"},{"type":"object","additionalProperties":false,"required":["allowHTTP1"],"properties":{"allowHTTP1":{"type":"boolean"}}}]}},"then":{"setDefaultValue":true}},"ignoreTrailingSlash":{"type":"boolean","default":false},"ignoreDuplicateSlashes":{"type":"boolean","default":false},"disableRequestLogging":{"type":"boolean","default":false},"jsonShorthand":{"type":"boolean","default":true},"maxParamLength":{"type":"integer","default":100},"onProtoPoisoning":{"type":"string","default":"error"},"onConstructorPoisoning":{"type":"string","default":"error"},"pluginTimeout":{"type":"integer","default":10000},"requestIdHeader":{"anyOf":[{"enum":[false]},{"type":"string"}],"default":"request-id"},"requestIdLogLabel":{"type":"string","default":"reqId"},"http2SessionTimeout":{"type":"integer","default":72000},"exposeHeadRoutes":{"type":"boolean","default":true},"useSemicolonDelimiter":{"type":"boolean","default":true},"versioning":{"type":"object","additionalProperties":true,"required":["storage","deriveVersion"],"properties":{"storage":{},"deriveVersion":{}}},"constraints":{"type":"object","additionalProperties":{"type":"object","required":["name","storage","validate","deriveConstraint"],"additionalProperties":true,"properties":{"name":{"type":"string"},"storage":{},"validate":{},"deriveConstraint":{}}}}}};
|
||||
const schema11 = {"type":"object","additionalProperties":false,"properties":{"connectionTimeout":{"type":"integer","default":0},"keepAliveTimeout":{"type":"integer","default":72000},"forceCloseConnections":{"oneOf":[{"type":"string","pattern":"idle"},{"type":"boolean"}]},"maxRequestsPerSocket":{"type":"integer","default":0,"nullable":true},"requestTimeout":{"type":"integer","default":0},"bodyLimit":{"type":"integer","default":1048576},"caseSensitive":{"type":"boolean","default":true},"allowUnsafeRegex":{"type":"boolean","default":false},"http2":{"type":"boolean"},"https":{"if":{"not":{"oneOf":[{"type":"boolean"},{"type":"null"},{"type":"object","additionalProperties":false,"required":["allowHTTP1"],"properties":{"allowHTTP1":{"type":"boolean"}}}]}},"then":{"setDefaultValue":true}},"ignoreTrailingSlash":{"type":"boolean","default":false},"ignoreDuplicateSlashes":{"type":"boolean","default":false},"disableRequestLogging":{"default":false},"maxParamLength":{"type":"integer","default":100},"onProtoPoisoning":{"type":"string","default":"error"},"onConstructorPoisoning":{"type":"string","default":"error"},"pluginTimeout":{"type":"integer","default":10000},"requestIdHeader":{"anyOf":[{"type":"boolean"},{"type":"string"}],"default":false},"requestIdLogLabel":{"type":"string","default":"reqId"},"http2SessionTimeout":{"type":"integer","default":72000},"exposeHeadRoutes":{"type":"boolean","default":true},"useSemicolonDelimiter":{"type":"boolean","default":false},"routerOptions":{"type":"object","additionalProperties":true,"properties":{"ignoreTrailingSlash":{"type":"boolean","default":false},"ignoreDuplicateSlashes":{"type":"boolean","default":false},"maxParamLength":{"type":"integer","default":100},"allowUnsafeRegex":{"type":"boolean","default":false},"useSemicolonDelimiter":{"type":"boolean","default":false}}},"constraints":{"type":"object","additionalProperties":{"type":"object","required":["name","storage","validate","deriveConstraint"],"additionalProperties":true,"properties":{"name":{"type":"string"},"storage":{},"validate":{},"deriveConstraint":{}}}}}};
|
||||
const func2 = Object.prototype.hasOwnProperty;
|
||||
const pattern0 = new RegExp("idle", "u");
|
||||
|
||||
@@ -42,9 +42,6 @@ data.ignoreDuplicateSlashes = false;
|
||||
if(data.disableRequestLogging === undefined){
|
||||
data.disableRequestLogging = false;
|
||||
}
|
||||
if(data.jsonShorthand === undefined){
|
||||
data.jsonShorthand = true;
|
||||
}
|
||||
if(data.maxParamLength === undefined){
|
||||
data.maxParamLength = 100;
|
||||
}
|
||||
@@ -58,7 +55,7 @@ if(data.pluginTimeout === undefined){
|
||||
data.pluginTimeout = 10000;
|
||||
}
|
||||
if(data.requestIdHeader === undefined){
|
||||
data.requestIdHeader = "request-id";
|
||||
data.requestIdHeader = false;
|
||||
}
|
||||
if(data.requestIdLogLabel === undefined){
|
||||
data.requestIdLogLabel = "reqId";
|
||||
@@ -70,7 +67,7 @@ if(data.exposeHeadRoutes === undefined){
|
||||
data.exposeHeadRoutes = true;
|
||||
}
|
||||
if(data.useSemicolonDelimiter === undefined){
|
||||
data.useSemicolonDelimiter = true;
|
||||
data.useSemicolonDelimiter = false;
|
||||
}
|
||||
const _errs1 = errors;
|
||||
for(const key0 in data){
|
||||
@@ -688,163 +685,122 @@ data["ignoreDuplicateSlashes"] = coerced14;
|
||||
}
|
||||
var valid0 = _errs43 === errors;
|
||||
if(valid0){
|
||||
let data13 = data.disableRequestLogging;
|
||||
let data13 = data.maxParamLength;
|
||||
const _errs45 = errors;
|
||||
if(typeof data13 !== "boolean"){
|
||||
if(!(((typeof data13 == "number") && (!(data13 % 1) && !isNaN(data13))) && (isFinite(data13)))){
|
||||
let dataType15 = typeof data13;
|
||||
let coerced15 = undefined;
|
||||
if(!(coerced15 !== undefined)){
|
||||
if(data13 === "false" || data13 === 0 || data13 === null){
|
||||
coerced15 = false;
|
||||
}
|
||||
else if(data13 === "true" || data13 === 1){
|
||||
coerced15 = true;
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/disableRequestLogging",schemaPath:"#/properties/disableRequestLogging/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced15 !== undefined){
|
||||
data13 = coerced15;
|
||||
if(data !== undefined){
|
||||
data["disableRequestLogging"] = coerced15;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid0 = _errs45 === errors;
|
||||
if(valid0){
|
||||
let data14 = data.jsonShorthand;
|
||||
const _errs47 = errors;
|
||||
if(typeof data14 !== "boolean"){
|
||||
let coerced16 = undefined;
|
||||
if(!(coerced16 !== undefined)){
|
||||
if(data14 === "false" || data14 === 0 || data14 === null){
|
||||
coerced16 = false;
|
||||
}
|
||||
else if(data14 === "true" || data14 === 1){
|
||||
coerced16 = true;
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/jsonShorthand",schemaPath:"#/properties/jsonShorthand/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced16 !== undefined){
|
||||
data14 = coerced16;
|
||||
if(data !== undefined){
|
||||
data["jsonShorthand"] = coerced16;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid0 = _errs47 === errors;
|
||||
if(valid0){
|
||||
let data15 = data.maxParamLength;
|
||||
const _errs49 = errors;
|
||||
if(!(((typeof data15 == "number") && (!(data15 % 1) && !isNaN(data15))) && (isFinite(data15)))){
|
||||
let dataType17 = typeof data15;
|
||||
let coerced17 = undefined;
|
||||
if(!(coerced17 !== undefined)){
|
||||
if(dataType17 === "boolean" || data15 === null
|
||||
|| (dataType17 === "string" && data15 && data15 == +data15 && !(data15 % 1))){
|
||||
coerced17 = +data15;
|
||||
if(dataType15 === "boolean" || data13 === null
|
||||
|| (dataType15 === "string" && data13 && data13 == +data13 && !(data13 % 1))){
|
||||
coerced15 = +data13;
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/maxParamLength",schemaPath:"#/properties/maxParamLength/type",keyword:"type",params:{type: "integer"},message:"must be integer"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced17 !== undefined){
|
||||
data15 = coerced17;
|
||||
if(coerced15 !== undefined){
|
||||
data13 = coerced15;
|
||||
if(data !== undefined){
|
||||
data["maxParamLength"] = coerced17;
|
||||
data["maxParamLength"] = coerced15;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid0 = _errs49 === errors;
|
||||
var valid0 = _errs45 === errors;
|
||||
if(valid0){
|
||||
let data16 = data.onProtoPoisoning;
|
||||
const _errs51 = errors;
|
||||
if(typeof data16 !== "string"){
|
||||
let dataType18 = typeof data16;
|
||||
let coerced18 = undefined;
|
||||
if(!(coerced18 !== undefined)){
|
||||
if(dataType18 == "number" || dataType18 == "boolean"){
|
||||
coerced18 = "" + data16;
|
||||
let data14 = data.onProtoPoisoning;
|
||||
const _errs47 = errors;
|
||||
if(typeof data14 !== "string"){
|
||||
let dataType16 = typeof data14;
|
||||
let coerced16 = undefined;
|
||||
if(!(coerced16 !== undefined)){
|
||||
if(dataType16 == "number" || dataType16 == "boolean"){
|
||||
coerced16 = "" + data14;
|
||||
}
|
||||
else if(data16 === null){
|
||||
coerced18 = "";
|
||||
else if(data14 === null){
|
||||
coerced16 = "";
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/onProtoPoisoning",schemaPath:"#/properties/onProtoPoisoning/type",keyword:"type",params:{type: "string"},message:"must be string"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced18 !== undefined){
|
||||
data16 = coerced18;
|
||||
if(coerced16 !== undefined){
|
||||
data14 = coerced16;
|
||||
if(data !== undefined){
|
||||
data["onProtoPoisoning"] = coerced18;
|
||||
data["onProtoPoisoning"] = coerced16;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid0 = _errs51 === errors;
|
||||
var valid0 = _errs47 === errors;
|
||||
if(valid0){
|
||||
let data17 = data.onConstructorPoisoning;
|
||||
const _errs53 = errors;
|
||||
if(typeof data17 !== "string"){
|
||||
let dataType19 = typeof data17;
|
||||
let coerced19 = undefined;
|
||||
if(!(coerced19 !== undefined)){
|
||||
if(dataType19 == "number" || dataType19 == "boolean"){
|
||||
coerced19 = "" + data17;
|
||||
let data15 = data.onConstructorPoisoning;
|
||||
const _errs49 = errors;
|
||||
if(typeof data15 !== "string"){
|
||||
let dataType17 = typeof data15;
|
||||
let coerced17 = undefined;
|
||||
if(!(coerced17 !== undefined)){
|
||||
if(dataType17 == "number" || dataType17 == "boolean"){
|
||||
coerced17 = "" + data15;
|
||||
}
|
||||
else if(data17 === null){
|
||||
coerced19 = "";
|
||||
else if(data15 === null){
|
||||
coerced17 = "";
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/onConstructorPoisoning",schemaPath:"#/properties/onConstructorPoisoning/type",keyword:"type",params:{type: "string"},message:"must be string"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced19 !== undefined){
|
||||
data17 = coerced19;
|
||||
if(coerced17 !== undefined){
|
||||
data15 = coerced17;
|
||||
if(data !== undefined){
|
||||
data["onConstructorPoisoning"] = coerced19;
|
||||
data["onConstructorPoisoning"] = coerced17;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid0 = _errs53 === errors;
|
||||
var valid0 = _errs49 === errors;
|
||||
if(valid0){
|
||||
let data18 = data.pluginTimeout;
|
||||
const _errs55 = errors;
|
||||
if(!(((typeof data18 == "number") && (!(data18 % 1) && !isNaN(data18))) && (isFinite(data18)))){
|
||||
let dataType20 = typeof data18;
|
||||
let coerced20 = undefined;
|
||||
if(!(coerced20 !== undefined)){
|
||||
if(dataType20 === "boolean" || data18 === null
|
||||
|| (dataType20 === "string" && data18 && data18 == +data18 && !(data18 % 1))){
|
||||
coerced20 = +data18;
|
||||
let data16 = data.pluginTimeout;
|
||||
const _errs51 = errors;
|
||||
if(!(((typeof data16 == "number") && (!(data16 % 1) && !isNaN(data16))) && (isFinite(data16)))){
|
||||
let dataType18 = typeof data16;
|
||||
let coerced18 = undefined;
|
||||
if(!(coerced18 !== undefined)){
|
||||
if(dataType18 === "boolean" || data16 === null
|
||||
|| (dataType18 === "string" && data16 && data16 == +data16 && !(data16 % 1))){
|
||||
coerced18 = +data16;
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/pluginTimeout",schemaPath:"#/properties/pluginTimeout/type",keyword:"type",params:{type: "integer"},message:"must be integer"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced20 !== undefined){
|
||||
data18 = coerced20;
|
||||
if(coerced18 !== undefined){
|
||||
data16 = coerced18;
|
||||
if(data !== undefined){
|
||||
data["pluginTimeout"] = coerced20;
|
||||
data["pluginTimeout"] = coerced18;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid0 = _errs55 === errors;
|
||||
var valid0 = _errs51 === errors;
|
||||
if(valid0){
|
||||
let data19 = data.requestIdHeader;
|
||||
const _errs57 = errors;
|
||||
const _errs58 = errors;
|
||||
let data17 = data.requestIdHeader;
|
||||
const _errs53 = errors;
|
||||
const _errs54 = errors;
|
||||
let valid6 = false;
|
||||
const _errs59 = errors;
|
||||
if(!(data19 === false)){
|
||||
const err12 = {instancePath:instancePath+"/requestIdHeader",schemaPath:"#/properties/requestIdHeader/anyOf/0/enum",keyword:"enum",params:{allowedValues: schema11.properties.requestIdHeader.anyOf[0].enum},message:"must be equal to one of the allowed values"};
|
||||
const _errs55 = errors;
|
||||
if(typeof data17 !== "boolean"){
|
||||
let coerced19 = undefined;
|
||||
if(!(coerced19 !== undefined)){
|
||||
if(data17 === "false" || data17 === 0 || data17 === null){
|
||||
coerced19 = false;
|
||||
}
|
||||
else if(data17 === "true" || data17 === 1){
|
||||
coerced19 = true;
|
||||
}
|
||||
else {
|
||||
const err12 = {instancePath:instancePath+"/requestIdHeader",schemaPath:"#/properties/requestIdHeader/anyOf/0/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"};
|
||||
if(vErrors === null){
|
||||
vErrors = [err12];
|
||||
}
|
||||
@@ -853,19 +809,27 @@ vErrors.push(err12);
|
||||
}
|
||||
errors++;
|
||||
}
|
||||
var _valid3 = _errs59 === errors;
|
||||
}
|
||||
if(coerced19 !== undefined){
|
||||
data17 = coerced19;
|
||||
if(data !== undefined){
|
||||
data["requestIdHeader"] = coerced19;
|
||||
}
|
||||
}
|
||||
}
|
||||
var _valid3 = _errs55 === errors;
|
||||
valid6 = valid6 || _valid3;
|
||||
if(!valid6){
|
||||
const _errs60 = errors;
|
||||
if(typeof data19 !== "string"){
|
||||
let dataType21 = typeof data19;
|
||||
let coerced21 = undefined;
|
||||
if(!(coerced21 !== undefined)){
|
||||
if(dataType21 == "number" || dataType21 == "boolean"){
|
||||
coerced21 = "" + data19;
|
||||
const _errs57 = errors;
|
||||
if(typeof data17 !== "string"){
|
||||
let dataType20 = typeof data17;
|
||||
let coerced20 = undefined;
|
||||
if(!(coerced20 !== undefined)){
|
||||
if(dataType20 == "number" || dataType20 == "boolean"){
|
||||
coerced20 = "" + data17;
|
||||
}
|
||||
else if(data19 === null){
|
||||
coerced21 = "";
|
||||
else if(data17 === null){
|
||||
coerced20 = "";
|
||||
}
|
||||
else {
|
||||
const err13 = {instancePath:instancePath+"/requestIdHeader",schemaPath:"#/properties/requestIdHeader/anyOf/1/type",keyword:"type",params:{type: "string"},message:"must be string"};
|
||||
@@ -878,14 +842,14 @@ vErrors.push(err13);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
if(coerced21 !== undefined){
|
||||
data19 = coerced21;
|
||||
if(coerced20 !== undefined){
|
||||
data17 = coerced20;
|
||||
if(data !== undefined){
|
||||
data["requestIdHeader"] = coerced21;
|
||||
data["requestIdHeader"] = coerced20;
|
||||
}
|
||||
}
|
||||
}
|
||||
var _valid3 = _errs60 === errors;
|
||||
var _valid3 = _errs57 === errors;
|
||||
valid6 = valid6 || _valid3;
|
||||
}
|
||||
if(!valid6){
|
||||
@@ -901,95 +865,140 @@ validate10.errors = vErrors;
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
errors = _errs58;
|
||||
errors = _errs54;
|
||||
if(vErrors !== null){
|
||||
if(_errs58){
|
||||
vErrors.length = _errs58;
|
||||
if(_errs54){
|
||||
vErrors.length = _errs54;
|
||||
}
|
||||
else {
|
||||
vErrors = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid0 = _errs57 === errors;
|
||||
var valid0 = _errs53 === errors;
|
||||
if(valid0){
|
||||
let data20 = data.requestIdLogLabel;
|
||||
const _errs62 = errors;
|
||||
if(typeof data20 !== "string"){
|
||||
let dataType22 = typeof data20;
|
||||
let coerced22 = undefined;
|
||||
if(!(coerced22 !== undefined)){
|
||||
if(dataType22 == "number" || dataType22 == "boolean"){
|
||||
coerced22 = "" + data20;
|
||||
let data18 = data.requestIdLogLabel;
|
||||
const _errs59 = errors;
|
||||
if(typeof data18 !== "string"){
|
||||
let dataType21 = typeof data18;
|
||||
let coerced21 = undefined;
|
||||
if(!(coerced21 !== undefined)){
|
||||
if(dataType21 == "number" || dataType21 == "boolean"){
|
||||
coerced21 = "" + data18;
|
||||
}
|
||||
else if(data20 === null){
|
||||
coerced22 = "";
|
||||
else if(data18 === null){
|
||||
coerced21 = "";
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/requestIdLogLabel",schemaPath:"#/properties/requestIdLogLabel/type",keyword:"type",params:{type: "string"},message:"must be string"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced22 !== undefined){
|
||||
data20 = coerced22;
|
||||
if(coerced21 !== undefined){
|
||||
data18 = coerced21;
|
||||
if(data !== undefined){
|
||||
data["requestIdLogLabel"] = coerced22;
|
||||
data["requestIdLogLabel"] = coerced21;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid0 = _errs62 === errors;
|
||||
var valid0 = _errs59 === errors;
|
||||
if(valid0){
|
||||
let data21 = data.http2SessionTimeout;
|
||||
const _errs64 = errors;
|
||||
if(!(((typeof data21 == "number") && (!(data21 % 1) && !isNaN(data21))) && (isFinite(data21)))){
|
||||
let dataType23 = typeof data21;
|
||||
let coerced23 = undefined;
|
||||
if(!(coerced23 !== undefined)){
|
||||
if(dataType23 === "boolean" || data21 === null
|
||||
|| (dataType23 === "string" && data21 && data21 == +data21 && !(data21 % 1))){
|
||||
coerced23 = +data21;
|
||||
let data19 = data.http2SessionTimeout;
|
||||
const _errs61 = errors;
|
||||
if(!(((typeof data19 == "number") && (!(data19 % 1) && !isNaN(data19))) && (isFinite(data19)))){
|
||||
let dataType22 = typeof data19;
|
||||
let coerced22 = undefined;
|
||||
if(!(coerced22 !== undefined)){
|
||||
if(dataType22 === "boolean" || data19 === null
|
||||
|| (dataType22 === "string" && data19 && data19 == +data19 && !(data19 % 1))){
|
||||
coerced22 = +data19;
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/http2SessionTimeout",schemaPath:"#/properties/http2SessionTimeout/type",keyword:"type",params:{type: "integer"},message:"must be integer"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced23 !== undefined){
|
||||
data21 = coerced23;
|
||||
if(coerced22 !== undefined){
|
||||
data19 = coerced22;
|
||||
if(data !== undefined){
|
||||
data["http2SessionTimeout"] = coerced23;
|
||||
data["http2SessionTimeout"] = coerced22;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid0 = _errs64 === errors;
|
||||
var valid0 = _errs61 === errors;
|
||||
if(valid0){
|
||||
let data22 = data.exposeHeadRoutes;
|
||||
const _errs66 = errors;
|
||||
if(typeof data22 !== "boolean"){
|
||||
let coerced24 = undefined;
|
||||
if(!(coerced24 !== undefined)){
|
||||
if(data22 === "false" || data22 === 0 || data22 === null){
|
||||
coerced24 = false;
|
||||
let data20 = data.exposeHeadRoutes;
|
||||
const _errs63 = errors;
|
||||
if(typeof data20 !== "boolean"){
|
||||
let coerced23 = undefined;
|
||||
if(!(coerced23 !== undefined)){
|
||||
if(data20 === "false" || data20 === 0 || data20 === null){
|
||||
coerced23 = false;
|
||||
}
|
||||
else if(data22 === "true" || data22 === 1){
|
||||
coerced24 = true;
|
||||
else if(data20 === "true" || data20 === 1){
|
||||
coerced23 = true;
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/exposeHeadRoutes",schemaPath:"#/properties/exposeHeadRoutes/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced24 !== undefined){
|
||||
data22 = coerced24;
|
||||
if(coerced23 !== undefined){
|
||||
data20 = coerced23;
|
||||
if(data !== undefined){
|
||||
data["exposeHeadRoutes"] = coerced24;
|
||||
data["exposeHeadRoutes"] = coerced23;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid0 = _errs66 === errors;
|
||||
var valid0 = _errs63 === errors;
|
||||
if(valid0){
|
||||
let data23 = data.useSemicolonDelimiter;
|
||||
const _errs68 = errors;
|
||||
let data21 = data.useSemicolonDelimiter;
|
||||
const _errs65 = errors;
|
||||
if(typeof data21 !== "boolean"){
|
||||
let coerced24 = undefined;
|
||||
if(!(coerced24 !== undefined)){
|
||||
if(data21 === "false" || data21 === 0 || data21 === null){
|
||||
coerced24 = false;
|
||||
}
|
||||
else if(data21 === "true" || data21 === 1){
|
||||
coerced24 = true;
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/useSemicolonDelimiter",schemaPath:"#/properties/useSemicolonDelimiter/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced24 !== undefined){
|
||||
data21 = coerced24;
|
||||
if(data !== undefined){
|
||||
data["useSemicolonDelimiter"] = coerced24;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid0 = _errs65 === errors;
|
||||
if(valid0){
|
||||
if(data.routerOptions !== undefined){
|
||||
let data22 = data.routerOptions;
|
||||
const _errs67 = errors;
|
||||
if(errors === _errs67){
|
||||
if(data22 && typeof data22 == "object" && !Array.isArray(data22)){
|
||||
if(data22.ignoreTrailingSlash === undefined){
|
||||
data22.ignoreTrailingSlash = false;
|
||||
}
|
||||
if(data22.ignoreDuplicateSlashes === undefined){
|
||||
data22.ignoreDuplicateSlashes = false;
|
||||
}
|
||||
if(data22.maxParamLength === undefined){
|
||||
data22.maxParamLength = 100;
|
||||
}
|
||||
if(data22.allowUnsafeRegex === undefined){
|
||||
data22.allowUnsafeRegex = false;
|
||||
}
|
||||
if(data22.useSemicolonDelimiter === undefined){
|
||||
data22.useSemicolonDelimiter = false;
|
||||
}
|
||||
let data23 = data22.ignoreTrailingSlash;
|
||||
const _errs70 = errors;
|
||||
if(typeof data23 !== "boolean"){
|
||||
let coerced25 = undefined;
|
||||
if(!(coerced25 !== undefined)){
|
||||
@@ -1000,78 +1009,170 @@ else if(data23 === "true" || data23 === 1){
|
||||
coerced25 = true;
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/useSemicolonDelimiter",schemaPath:"#/properties/useSemicolonDelimiter/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}];
|
||||
validate10.errors = [{instancePath:instancePath+"/routerOptions/ignoreTrailingSlash",schemaPath:"#/properties/routerOptions/properties/ignoreTrailingSlash/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced25 !== undefined){
|
||||
data23 = coerced25;
|
||||
if(data !== undefined){
|
||||
data["useSemicolonDelimiter"] = coerced25;
|
||||
if(data22 !== undefined){
|
||||
data22["ignoreTrailingSlash"] = coerced25;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid0 = _errs68 === errors;
|
||||
if(valid0){
|
||||
if(data.versioning !== undefined){
|
||||
let data24 = data.versioning;
|
||||
const _errs70 = errors;
|
||||
if(errors === _errs70){
|
||||
if(data24 && typeof data24 == "object" && !Array.isArray(data24)){
|
||||
let missing1;
|
||||
if(((data24.storage === undefined) && (missing1 = "storage")) || ((data24.deriveVersion === undefined) && (missing1 = "deriveVersion"))){
|
||||
validate10.errors = [{instancePath:instancePath+"/versioning",schemaPath:"#/properties/versioning/required",keyword:"required",params:{missingProperty: missing1},message:"must have required property '"+missing1+"'"}];
|
||||
var valid7 = _errs70 === errors;
|
||||
if(valid7){
|
||||
let data24 = data22.ignoreDuplicateSlashes;
|
||||
const _errs72 = errors;
|
||||
if(typeof data24 !== "boolean"){
|
||||
let coerced26 = undefined;
|
||||
if(!(coerced26 !== undefined)){
|
||||
if(data24 === "false" || data24 === 0 || data24 === null){
|
||||
coerced26 = false;
|
||||
}
|
||||
else if(data24 === "true" || data24 === 1){
|
||||
coerced26 = true;
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/routerOptions/ignoreDuplicateSlashes",schemaPath:"#/properties/routerOptions/properties/ignoreDuplicateSlashes/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced26 !== undefined){
|
||||
data24 = coerced26;
|
||||
if(data22 !== undefined){
|
||||
data22["ignoreDuplicateSlashes"] = coerced26;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid7 = _errs72 === errors;
|
||||
if(valid7){
|
||||
let data25 = data22.maxParamLength;
|
||||
const _errs74 = errors;
|
||||
if(!(((typeof data25 == "number") && (!(data25 % 1) && !isNaN(data25))) && (isFinite(data25)))){
|
||||
let dataType27 = typeof data25;
|
||||
let coerced27 = undefined;
|
||||
if(!(coerced27 !== undefined)){
|
||||
if(dataType27 === "boolean" || data25 === null
|
||||
|| (dataType27 === "string" && data25 && data25 == +data25 && !(data25 % 1))){
|
||||
coerced27 = +data25;
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/routerOptions/maxParamLength",schemaPath:"#/properties/routerOptions/properties/maxParamLength/type",keyword:"type",params:{type: "integer"},message:"must be integer"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced27 !== undefined){
|
||||
data25 = coerced27;
|
||||
if(data22 !== undefined){
|
||||
data22["maxParamLength"] = coerced27;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid7 = _errs74 === errors;
|
||||
if(valid7){
|
||||
let data26 = data22.allowUnsafeRegex;
|
||||
const _errs76 = errors;
|
||||
if(typeof data26 !== "boolean"){
|
||||
let coerced28 = undefined;
|
||||
if(!(coerced28 !== undefined)){
|
||||
if(data26 === "false" || data26 === 0 || data26 === null){
|
||||
coerced28 = false;
|
||||
}
|
||||
else if(data26 === "true" || data26 === 1){
|
||||
coerced28 = true;
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/routerOptions/allowUnsafeRegex",schemaPath:"#/properties/routerOptions/properties/allowUnsafeRegex/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced28 !== undefined){
|
||||
data26 = coerced28;
|
||||
if(data22 !== undefined){
|
||||
data22["allowUnsafeRegex"] = coerced28;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid7 = _errs76 === errors;
|
||||
if(valid7){
|
||||
let data27 = data22.useSemicolonDelimiter;
|
||||
const _errs78 = errors;
|
||||
if(typeof data27 !== "boolean"){
|
||||
let coerced29 = undefined;
|
||||
if(!(coerced29 !== undefined)){
|
||||
if(data27 === "false" || data27 === 0 || data27 === null){
|
||||
coerced29 = false;
|
||||
}
|
||||
else if(data27 === "true" || data27 === 1){
|
||||
coerced29 = true;
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/routerOptions/useSemicolonDelimiter",schemaPath:"#/properties/routerOptions/properties/useSemicolonDelimiter/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced29 !== undefined){
|
||||
data27 = coerced29;
|
||||
if(data22 !== undefined){
|
||||
data22["useSemicolonDelimiter"] = coerced29;
|
||||
}
|
||||
}
|
||||
}
|
||||
var valid7 = _errs78 === errors;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/versioning",schemaPath:"#/properties/versioning/type",keyword:"type",params:{type: "object"},message:"must be object"}];
|
||||
validate10.errors = [{instancePath:instancePath+"/routerOptions",schemaPath:"#/properties/routerOptions/type",keyword:"type",params:{type: "object"},message:"must be object"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
var valid0 = _errs70 === errors;
|
||||
var valid0 = _errs67 === errors;
|
||||
}
|
||||
else {
|
||||
var valid0 = true;
|
||||
}
|
||||
if(valid0){
|
||||
if(data.constraints !== undefined){
|
||||
let data25 = data.constraints;
|
||||
const _errs73 = errors;
|
||||
if(errors === _errs73){
|
||||
if(data25 && typeof data25 == "object" && !Array.isArray(data25)){
|
||||
for(const key2 in data25){
|
||||
let data26 = data25[key2];
|
||||
const _errs76 = errors;
|
||||
if(errors === _errs76){
|
||||
if(data26 && typeof data26 == "object" && !Array.isArray(data26)){
|
||||
let missing2;
|
||||
if(((((data26.name === undefined) && (missing2 = "name")) || ((data26.storage === undefined) && (missing2 = "storage"))) || ((data26.validate === undefined) && (missing2 = "validate"))) || ((data26.deriveConstraint === undefined) && (missing2 = "deriveConstraint"))){
|
||||
validate10.errors = [{instancePath:instancePath+"/constraints/" + key2.replace(/~/g, "~0").replace(/\//g, "~1"),schemaPath:"#/properties/constraints/additionalProperties/required",keyword:"required",params:{missingProperty: missing2},message:"must have required property '"+missing2+"'"}];
|
||||
let data28 = data.constraints;
|
||||
const _errs80 = errors;
|
||||
if(errors === _errs80){
|
||||
if(data28 && typeof data28 == "object" && !Array.isArray(data28)){
|
||||
for(const key2 in data28){
|
||||
let data29 = data28[key2];
|
||||
const _errs83 = errors;
|
||||
if(errors === _errs83){
|
||||
if(data29 && typeof data29 == "object" && !Array.isArray(data29)){
|
||||
let missing1;
|
||||
if(((((data29.name === undefined) && (missing1 = "name")) || ((data29.storage === undefined) && (missing1 = "storage"))) || ((data29.validate === undefined) && (missing1 = "validate"))) || ((data29.deriveConstraint === undefined) && (missing1 = "deriveConstraint"))){
|
||||
validate10.errors = [{instancePath:instancePath+"/constraints/" + key2.replace(/~/g, "~0").replace(/\//g, "~1"),schemaPath:"#/properties/constraints/additionalProperties/required",keyword:"required",params:{missingProperty: missing1},message:"must have required property '"+missing1+"'"}];
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if(data26.name !== undefined){
|
||||
let data27 = data26.name;
|
||||
if(typeof data27 !== "string"){
|
||||
let dataType26 = typeof data27;
|
||||
let coerced26 = undefined;
|
||||
if(!(coerced26 !== undefined)){
|
||||
if(dataType26 == "number" || dataType26 == "boolean"){
|
||||
coerced26 = "" + data27;
|
||||
if(data29.name !== undefined){
|
||||
let data30 = data29.name;
|
||||
if(typeof data30 !== "string"){
|
||||
let dataType30 = typeof data30;
|
||||
let coerced30 = undefined;
|
||||
if(!(coerced30 !== undefined)){
|
||||
if(dataType30 == "number" || dataType30 == "boolean"){
|
||||
coerced30 = "" + data30;
|
||||
}
|
||||
else if(data27 === null){
|
||||
coerced26 = "";
|
||||
else if(data30 === null){
|
||||
coerced30 = "";
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath:instancePath+"/constraints/" + key2.replace(/~/g, "~0").replace(/\//g, "~1")+"/name",schemaPath:"#/properties/constraints/additionalProperties/properties/name/type",keyword:"type",params:{type: "string"},message:"must be string"}];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(coerced26 !== undefined){
|
||||
data27 = coerced26;
|
||||
if(data26 !== undefined){
|
||||
data26["name"] = coerced26;
|
||||
if(coerced30 !== undefined){
|
||||
data30 = coerced30;
|
||||
if(data29 !== undefined){
|
||||
data29["name"] = coerced30;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1083,8 +1184,8 @@ validate10.errors = [{instancePath:instancePath+"/constraints/" + key2.replace(/
|
||||
return false;
|
||||
}
|
||||
}
|
||||
var valid7 = _errs76 === errors;
|
||||
if(!valid7){
|
||||
var valid8 = _errs83 === errors;
|
||||
if(!valid8){
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1094,7 +1195,7 @@ validate10.errors = [{instancePath:instancePath+"/constraints",schemaPath:"#/pro
|
||||
return false;
|
||||
}
|
||||
}
|
||||
var valid0 = _errs73 === errors;
|
||||
var valid0 = _errs80 === errors;
|
||||
}
|
||||
else {
|
||||
var valid0 = true;
|
||||
@@ -1123,8 +1224,6 @@ var valid0 = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
validate10.errors = [{instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"}];
|
||||
return false;
|
||||
@@ -1135,4 +1234,5 @@ return errors === 0;
|
||||
}
|
||||
|
||||
|
||||
module.exports.defaultInitOptions = {"connectionTimeout":0,"keepAliveTimeout":72000,"maxRequestsPerSocket":0,"requestTimeout":0,"bodyLimit":1048576,"caseSensitive":true,"allowUnsafeRegex":false,"disableRequestLogging":false,"jsonShorthand":true,"ignoreTrailingSlash":false,"ignoreDuplicateSlashes":false,"maxParamLength":100,"onProtoPoisoning":"error","onConstructorPoisoning":"error","pluginTimeout":10000,"requestIdHeader":"request-id","requestIdLogLabel":"reqId","http2SessionTimeout":72000,"exposeHeadRoutes":true,"useSemicolonDelimiter":true}
|
||||
module.exports.defaultInitOptions = {"connectionTimeout":0,"keepAliveTimeout":72000,"maxRequestsPerSocket":0,"requestTimeout":0,"bodyLimit":1048576,"caseSensitive":true,"allowUnsafeRegex":false,"disableRequestLogging":false,"ignoreTrailingSlash":false,"ignoreDuplicateSlashes":false,"maxParamLength":100,"onProtoPoisoning":"error","onConstructorPoisoning":"error","pluginTimeout":10000,"requestIdHeader":false,"requestIdLogLabel":"reqId","http2SessionTimeout":72000,"exposeHeadRoutes":true,"useSemicolonDelimiter":false,"allowErrorHandlerOverride":true,"routerOptions":{"ignoreTrailingSlash":false,"ignoreDuplicateSlashes":false,"maxParamLength":100,"allowUnsafeRegex":false,"useSemicolonDelimiter":false}}
|
||||
/* c8 ignore stop */
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
const { AsyncResource } = require('node:async_hooks')
|
||||
const { FifoMap: Fifo } = require('toad-cache')
|
||||
const { safeParse: safeParseContentType, defaultContentType } = require('fast-content-type-parse')
|
||||
const secureJson = require('secure-json-parse')
|
||||
const { parse: secureJsonParse } = require('secure-json-parse')
|
||||
const {
|
||||
kDefaultJsonParse,
|
||||
kContentTypeParser,
|
||||
@@ -25,8 +24,10 @@ const {
|
||||
FST_ERR_CTP_INVALID_MEDIA_TYPE,
|
||||
FST_ERR_CTP_INVALID_CONTENT_LENGTH,
|
||||
FST_ERR_CTP_EMPTY_JSON_BODY,
|
||||
FST_ERR_CTP_INSTANCE_ALREADY_STARTED
|
||||
FST_ERR_CTP_INSTANCE_ALREADY_STARTED,
|
||||
FST_ERR_CTP_INVALID_JSON_BODY
|
||||
} = require('./errors')
|
||||
const { FSTSEC001 } = require('./warnings')
|
||||
|
||||
function ContentTypeParser (bodyLimit, onProtoPoisoning, onConstructorPoisoning) {
|
||||
this[kDefaultJsonParse] = getDefaultJsonParser(onProtoPoisoning, onConstructorPoisoning)
|
||||
@@ -34,7 +35,7 @@ function ContentTypeParser (bodyLimit, onProtoPoisoning, onConstructorPoisoning)
|
||||
this.customParsers = new Map()
|
||||
this.customParsers.set('application/json', new Parser(true, false, bodyLimit, this[kDefaultJsonParse]))
|
||||
this.customParsers.set('text/plain', new Parser(true, false, bodyLimit, defaultPlainTextParser))
|
||||
this.parserList = [new ParserListItem('application/json'), new ParserListItem('text/plain')]
|
||||
this.parserList = ['application/json', 'text/plain']
|
||||
this.parserRegExpList = []
|
||||
this.cache = new Fifo(100)
|
||||
}
|
||||
@@ -42,9 +43,16 @@ function ContentTypeParser (bodyLimit, onProtoPoisoning, onConstructorPoisoning)
|
||||
ContentTypeParser.prototype.add = function (contentType, opts, parserFn) {
|
||||
const contentTypeIsString = typeof contentType === 'string'
|
||||
|
||||
if (!contentTypeIsString && !(contentType instanceof RegExp)) throw new FST_ERR_CTP_INVALID_TYPE()
|
||||
if (contentTypeIsString && contentType.length === 0) throw new FST_ERR_CTP_EMPTY_TYPE()
|
||||
if (typeof parserFn !== 'function') throw new FST_ERR_CTP_INVALID_HANDLER()
|
||||
if (contentTypeIsString) {
|
||||
contentType = contentType.trim().toLowerCase()
|
||||
if (contentType.length === 0) throw new FST_ERR_CTP_EMPTY_TYPE()
|
||||
} else if (!(contentType instanceof RegExp)) {
|
||||
throw new FST_ERR_CTP_INVALID_TYPE()
|
||||
}
|
||||
|
||||
if (typeof parserFn !== 'function') {
|
||||
throw new FST_ERR_CTP_INVALID_HANDLER()
|
||||
}
|
||||
|
||||
if (this.existingParser(contentType)) {
|
||||
throw new FST_ERR_CTP_ALREADY_PRESENT(contentType)
|
||||
@@ -63,21 +71,29 @@ ContentTypeParser.prototype.add = function (contentType, opts, parserFn) {
|
||||
parserFn
|
||||
)
|
||||
|
||||
if (contentTypeIsString && contentType === '*') {
|
||||
if (contentType === '*') {
|
||||
this.customParsers.set('', parser)
|
||||
} else {
|
||||
if (contentTypeIsString) {
|
||||
this.parserList.unshift(new ParserListItem(contentType))
|
||||
this.parserList.unshift(contentType)
|
||||
this.customParsers.set(contentType, parser)
|
||||
} else {
|
||||
contentType.isEssence = contentType.source.indexOf(';') === -1
|
||||
validateRegExp(contentType)
|
||||
this.parserRegExpList.unshift(contentType)
|
||||
this.customParsers.set(contentType.toString(), parser)
|
||||
}
|
||||
this.customParsers.set(contentType.toString(), parser)
|
||||
}
|
||||
}
|
||||
|
||||
ContentTypeParser.prototype.hasParser = function (contentType) {
|
||||
return this.customParsers.has(typeof contentType === 'string' ? contentType : contentType.toString())
|
||||
if (typeof contentType === 'string') {
|
||||
contentType = contentType.trim().toLowerCase()
|
||||
} else {
|
||||
if (!(contentType instanceof RegExp)) throw new FST_ERR_CTP_INVALID_TYPE()
|
||||
contentType = contentType.toString()
|
||||
}
|
||||
|
||||
return this.customParsers.has(contentType)
|
||||
}
|
||||
|
||||
ContentTypeParser.prototype.existingParser = function (contentType) {
|
||||
@@ -92,38 +108,33 @@ ContentTypeParser.prototype.existingParser = function (contentType) {
|
||||
}
|
||||
|
||||
ContentTypeParser.prototype.getParser = function (contentType) {
|
||||
if (this.hasParser(contentType)) {
|
||||
return this.customParsers.get(contentType)
|
||||
}
|
||||
|
||||
const parser = this.cache.get(contentType)
|
||||
let parser = this.customParsers.get(contentType)
|
||||
if (parser !== undefined) return parser
|
||||
parser = this.cache.get(contentType)
|
||||
if (parser !== undefined) return parser
|
||||
|
||||
const parsed = safeParseContentType(contentType)
|
||||
|
||||
// dummyContentType always the same object
|
||||
// we can use === for the comparison and return early
|
||||
if (parsed === defaultContentType) {
|
||||
return this.customParsers.get('')
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
for (var i = 0; i !== this.parserList.length; ++i) {
|
||||
const caseInsensitiveContentType = contentType.toLowerCase()
|
||||
for (let i = 0; i !== this.parserList.length; ++i) {
|
||||
const parserListItem = this.parserList[i]
|
||||
if (compareContentType(parsed, parserListItem)) {
|
||||
const parser = this.customParsers.get(parserListItem.name)
|
||||
// we set request content-type in cache to reduce parsing of MIME type
|
||||
if (
|
||||
caseInsensitiveContentType.slice(0, parserListItem.length) === parserListItem &&
|
||||
(
|
||||
caseInsensitiveContentType.length === parserListItem.length ||
|
||||
caseInsensitiveContentType.charCodeAt(parserListItem.length) === 59 /* `;` */ ||
|
||||
caseInsensitiveContentType.charCodeAt(parserListItem.length) === 32 /* ` ` */ ||
|
||||
caseInsensitiveContentType.charCodeAt(parserListItem.length) === 9 /* `\t` */
|
||||
)
|
||||
) {
|
||||
parser = this.customParsers.get(parserListItem)
|
||||
this.cache.set(contentType, parser)
|
||||
return parser
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
for (var j = 0; j !== this.parserRegExpList.length; ++j) {
|
||||
for (let j = 0; j !== this.parserRegExpList.length; ++j) {
|
||||
const parserRegExp = this.parserRegExpList[j]
|
||||
if (compareRegExpContentType(contentType, parsed.type, parserRegExp)) {
|
||||
const parser = this.customParsers.get(parserRegExp.toString())
|
||||
// we set request content-type in cache to reduce parsing of MIME type
|
||||
if (parserRegExp.test(contentType)) {
|
||||
parser = this.customParsers.get(parserRegExp.toString())
|
||||
this.cache.set(contentType, parser)
|
||||
return parser
|
||||
}
|
||||
@@ -140,13 +151,19 @@ ContentTypeParser.prototype.removeAll = function () {
|
||||
}
|
||||
|
||||
ContentTypeParser.prototype.remove = function (contentType) {
|
||||
if (!(typeof contentType === 'string' || contentType instanceof RegExp)) throw new FST_ERR_CTP_INVALID_TYPE()
|
||||
let parsers
|
||||
|
||||
const removed = this.customParsers.delete(contentType.toString())
|
||||
if (typeof contentType === 'string') {
|
||||
contentType = contentType.trim().toLowerCase()
|
||||
parsers = this.parserList
|
||||
} else {
|
||||
if (!(contentType instanceof RegExp)) throw new FST_ERR_CTP_INVALID_TYPE()
|
||||
contentType = contentType.toString()
|
||||
parsers = this.parserRegExpList
|
||||
}
|
||||
|
||||
const parsers = typeof contentType === 'string' ? this.parserList : this.parserRegExpList
|
||||
|
||||
const idx = parsers.findIndex(ct => ct.toString() === contentType.toString())
|
||||
const removed = this.customParsers.delete(contentType)
|
||||
const idx = parsers.findIndex(ct => ct.toString() === contentType)
|
||||
|
||||
if (idx > -1) {
|
||||
parsers.splice(idx, 1)
|
||||
@@ -159,17 +176,18 @@ ContentTypeParser.prototype.run = function (contentType, handler, request, reply
|
||||
const parser = this.getParser(contentType)
|
||||
|
||||
if (parser === undefined) {
|
||||
if (request.is404) {
|
||||
if (request.is404 === true) {
|
||||
handler(request, reply)
|
||||
} else {
|
||||
reply.send(new FST_ERR_CTP_INVALID_MEDIA_TYPE(contentType || undefined))
|
||||
return
|
||||
}
|
||||
|
||||
// Early return to avoid allocating an AsyncResource if it's not needed
|
||||
reply[kReplyIsError] = true
|
||||
reply.send(new FST_ERR_CTP_INVALID_MEDIA_TYPE(contentType || undefined))
|
||||
return
|
||||
}
|
||||
|
||||
const resource = new AsyncResource('content-type-parser:run', request)
|
||||
const done = resource.bind(onDone)
|
||||
|
||||
if (parser.asString === true || parser.asBuffer === true) {
|
||||
rawBody(
|
||||
@@ -179,50 +197,44 @@ ContentTypeParser.prototype.run = function (contentType, handler, request, reply
|
||||
parser,
|
||||
done
|
||||
)
|
||||
} else {
|
||||
const result = parser.fn(request, request[kRequestPayloadStream], done)
|
||||
|
||||
if (result && typeof result.then === 'function') {
|
||||
result.then(body => done(null, body), done)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
function done (error, body) {
|
||||
// We cannot use resource.bind() because it is broken in node v12 and v14
|
||||
resource.runInAsyncScope(() => {
|
||||
resource.emitDestroy()
|
||||
if (error) {
|
||||
reply[kReplyIsError] = true
|
||||
reply.send(error)
|
||||
} else {
|
||||
request.body = body
|
||||
handler(request, reply)
|
||||
}
|
||||
})
|
||||
const result = parser.fn(request, request[kRequestPayloadStream], done)
|
||||
if (result && typeof result.then === 'function') {
|
||||
result.then(body => { done(null, body) }, done)
|
||||
}
|
||||
|
||||
function onDone (error, body) {
|
||||
resource.emitDestroy()
|
||||
if (error != null) {
|
||||
// We must close the connection as the client may
|
||||
// send more data
|
||||
reply.header('connection', 'close')
|
||||
reply[kReplyIsError] = true
|
||||
reply.send(error)
|
||||
return
|
||||
}
|
||||
request.body = body
|
||||
handler(request, reply)
|
||||
}
|
||||
}
|
||||
|
||||
function rawBody (request, reply, options, parser, done) {
|
||||
const asString = parser.asString
|
||||
const asString = parser.asString === true
|
||||
const limit = options.limit === null ? parser.bodyLimit : options.limit
|
||||
const contentLength = request.headers['content-length'] === undefined
|
||||
? NaN
|
||||
: Number(request.headers['content-length'])
|
||||
const contentLength = Number(request.headers['content-length'])
|
||||
|
||||
if (contentLength > limit) {
|
||||
// We must close the connection as the client is going
|
||||
// to send this data anyway
|
||||
reply.header('connection', 'close')
|
||||
reply.send(new FST_ERR_CTP_BODY_TOO_LARGE())
|
||||
done(new FST_ERR_CTP_BODY_TOO_LARGE(), undefined)
|
||||
return
|
||||
}
|
||||
|
||||
let receivedLength = 0
|
||||
let body = asString === true ? '' : []
|
||||
|
||||
let body = asString ? '' : []
|
||||
const payload = request[kRequestPayloadStream] || request.raw
|
||||
|
||||
if (asString === true) {
|
||||
if (asString) {
|
||||
payload.setEncoding('utf8')
|
||||
}
|
||||
|
||||
@@ -232,7 +244,7 @@ function rawBody (request, reply, options, parser, done) {
|
||||
payload.resume()
|
||||
|
||||
function onData (chunk) {
|
||||
receivedLength += chunk.length
|
||||
receivedLength += asString ? Buffer.byteLength(chunk) : chunk.length
|
||||
const { receivedEncodedLength = 0 } = payload
|
||||
// The resulting body length must not exceed bodyLimit (see "zip bomb").
|
||||
// The case when encoded length is larger than received length is rather theoretical,
|
||||
@@ -241,11 +253,11 @@ function rawBody (request, reply, options, parser, done) {
|
||||
payload.removeListener('data', onData)
|
||||
payload.removeListener('end', onEnd)
|
||||
payload.removeListener('error', onEnd)
|
||||
reply.send(new FST_ERR_CTP_BODY_TOO_LARGE())
|
||||
done(new FST_ERR_CTP_BODY_TOO_LARGE(), undefined)
|
||||
return
|
||||
}
|
||||
|
||||
if (asString === true) {
|
||||
if (asString) {
|
||||
body += chunk
|
||||
} else {
|
||||
body.push(chunk)
|
||||
@@ -257,51 +269,45 @@ function rawBody (request, reply, options, parser, done) {
|
||||
payload.removeListener('end', onEnd)
|
||||
payload.removeListener('error', onEnd)
|
||||
|
||||
if (err !== undefined) {
|
||||
if (err != null) {
|
||||
if (!(typeof err.statusCode === 'number' && err.statusCode >= 400)) {
|
||||
err.statusCode = 400
|
||||
}
|
||||
reply[kReplyIsError] = true
|
||||
reply.code(err.statusCode).send(err)
|
||||
done(err, undefined)
|
||||
return
|
||||
}
|
||||
|
||||
if (asString === true) {
|
||||
receivedLength = Buffer.byteLength(body)
|
||||
}
|
||||
|
||||
if (!Number.isNaN(contentLength) && (payload.receivedEncodedLength || receivedLength) !== contentLength) {
|
||||
reply.header('connection', 'close')
|
||||
reply.send(new FST_ERR_CTP_INVALID_CONTENT_LENGTH())
|
||||
done(new FST_ERR_CTP_INVALID_CONTENT_LENGTH(), undefined)
|
||||
return
|
||||
}
|
||||
|
||||
if (asString === false) {
|
||||
if (!asString) {
|
||||
body = Buffer.concat(body)
|
||||
}
|
||||
|
||||
const result = parser.fn(request, body, done)
|
||||
if (result && typeof result.then === 'function') {
|
||||
result.then(body => done(null, body), done)
|
||||
result.then(body => { done(null, body) }, done)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getDefaultJsonParser (onProtoPoisoning, onConstructorPoisoning) {
|
||||
const parseOptions = { protoAction: onProtoPoisoning, constructorAction: onConstructorPoisoning }
|
||||
|
||||
return defaultJsonParser
|
||||
|
||||
function defaultJsonParser (req, body, done) {
|
||||
if (body === '' || body == null || (Buffer.isBuffer(body) && body.length === 0)) {
|
||||
return done(new FST_ERR_CTP_EMPTY_JSON_BODY(), undefined)
|
||||
if (body.length === 0) {
|
||||
done(new FST_ERR_CTP_EMPTY_JSON_BODY(), undefined)
|
||||
return
|
||||
}
|
||||
let json
|
||||
try {
|
||||
json = secureJson.parse(body, { protoAction: onProtoPoisoning, constructorAction: onConstructorPoisoning })
|
||||
} catch (err) {
|
||||
err.statusCode = 400
|
||||
return done(err, undefined)
|
||||
done(null, secureJsonParse(body, parseOptions))
|
||||
} catch {
|
||||
done(new FST_ERR_CTP_INVALID_JSON_BODY(), undefined)
|
||||
}
|
||||
done(null, json)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,60 +379,15 @@ function removeAllContentTypeParsers () {
|
||||
this[kContentTypeParser].removeAll()
|
||||
}
|
||||
|
||||
function compareContentType (contentType, parserListItem) {
|
||||
if (parserListItem.isEssence) {
|
||||
// we do essence check
|
||||
return contentType.type.indexOf(parserListItem) !== -1
|
||||
} else {
|
||||
// when the content-type includes parameters
|
||||
// we do a full-text search
|
||||
// reject essence content-type before checking parameters
|
||||
if (contentType.type.indexOf(parserListItem.type) === -1) return false
|
||||
for (const key of parserListItem.parameterKeys) {
|
||||
// reject when missing parameters
|
||||
if (!(key in contentType.parameters)) return false
|
||||
// reject when parameters do not match
|
||||
if (contentType.parameters[key] !== parserListItem.parameters[key]) return false
|
||||
}
|
||||
return true
|
||||
function validateRegExp (regexp) {
|
||||
// RegExp should either start with ^ or include ;?
|
||||
// It can ensure the user is properly detect the essence
|
||||
// MIME types.
|
||||
if (regexp.source[0] !== '^' && regexp.source.includes(';?') === false) {
|
||||
FSTSEC001(regexp.source)
|
||||
}
|
||||
}
|
||||
|
||||
function compareRegExpContentType (contentType, essenceMIMEType, regexp) {
|
||||
if (regexp.isEssence) {
|
||||
// we do essence check
|
||||
return regexp.test(essenceMIMEType)
|
||||
} else {
|
||||
// when the content-type includes parameters
|
||||
// we do a full-text match
|
||||
return regexp.test(contentType)
|
||||
}
|
||||
}
|
||||
|
||||
function ParserListItem (contentType) {
|
||||
this.name = contentType
|
||||
// we pre-calculate all the needed information
|
||||
// before content-type comparison
|
||||
const parsed = safeParseContentType(contentType)
|
||||
this.isEssence = contentType.indexOf(';') === -1
|
||||
// we should not allow empty string for parser list item
|
||||
// because it would become a match-all handler
|
||||
if (this.isEssence === false && parsed.type === '') {
|
||||
// handle semicolon or empty string
|
||||
const tmp = contentType.split(';', 1)[0]
|
||||
this.type = tmp === '' ? contentType : tmp
|
||||
} else {
|
||||
this.type = parsed.type
|
||||
}
|
||||
this.parameters = parsed.parameters
|
||||
this.parameterKeys = Object.keys(parsed.parameters)
|
||||
}
|
||||
|
||||
// used in ContentTypeParser.remove
|
||||
ParserListItem.prototype.toString = function () {
|
||||
return this.name
|
||||
}
|
||||
|
||||
module.exports = ContentTypeParser
|
||||
module.exports.helpers = {
|
||||
buildContentTypeParser,
|
||||
26
backend/node_modules/fastify/lib/context.js
generated
vendored
26
backend/node_modules/fastify/lib/context.js
generated
vendored
@@ -14,8 +14,7 @@ const {
|
||||
kContentTypeParser,
|
||||
kRouteByFastify,
|
||||
kRequestCacheValidateFns,
|
||||
kReplyCacheSerializeFns,
|
||||
kPublicRouteContext
|
||||
kReplyCacheSerializeFns
|
||||
} = require('./symbols.js')
|
||||
|
||||
// Object that holds the context of every request
|
||||
@@ -79,35 +78,14 @@ function Context ({
|
||||
this.validatorCompiler = validatorCompiler || null
|
||||
this.serializerCompiler = serializerCompiler || null
|
||||
|
||||
// Route + Userland configurations for the route
|
||||
this[kPublicRouteContext] = getPublicRouteContext(this)
|
||||
|
||||
this.server = server
|
||||
}
|
||||
|
||||
function getPublicRouteContext (context) {
|
||||
return Object.create(null, {
|
||||
schema: {
|
||||
enumerable: true,
|
||||
get () {
|
||||
return context.schema
|
||||
}
|
||||
},
|
||||
config: {
|
||||
enumerable: true,
|
||||
get () {
|
||||
return context.config
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function defaultSchemaErrorFormatter (errors, dataVar) {
|
||||
let text = ''
|
||||
const separator = ', '
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
for (var i = 0; i !== errors.length; ++i) {
|
||||
for (let i = 0; i !== errors.length; ++i) {
|
||||
const e = errors[i]
|
||||
text += dataVar + (e.instancePath || '') + ' ' + e.message + separator
|
||||
}
|
||||
|
||||
33
backend/node_modules/fastify/lib/decorate.js
generated
vendored
33
backend/node_modules/fastify/lib/decorate.js
generated
vendored
@@ -1,7 +1,5 @@
|
||||
'use strict'
|
||||
|
||||
/* eslint no-prototype-builtins: 0 */
|
||||
|
||||
const {
|
||||
kReply,
|
||||
kRequest,
|
||||
@@ -13,13 +11,13 @@ const {
|
||||
FST_ERR_DEC_ALREADY_PRESENT,
|
||||
FST_ERR_DEC_MISSING_DEPENDENCY,
|
||||
FST_ERR_DEC_AFTER_START,
|
||||
FST_ERR_DEC_DEPENDENCY_INVALID_TYPE
|
||||
FST_ERR_DEC_REFERENCE_TYPE,
|
||||
FST_ERR_DEC_DEPENDENCY_INVALID_TYPE,
|
||||
FST_ERR_DEC_UNDECLARED
|
||||
} = require('./errors')
|
||||
|
||||
const { FSTDEP006 } = require('./warnings')
|
||||
|
||||
function decorate (instance, name, fn, dependencies) {
|
||||
if (Object.prototype.hasOwnProperty.call(instance, name)) {
|
||||
if (Object.hasOwn(instance, name)) {
|
||||
throw new FST_ERR_DEC_ALREADY_PRESENT(name)
|
||||
}
|
||||
|
||||
@@ -35,9 +33,21 @@ function decorate (instance, name, fn, dependencies) {
|
||||
}
|
||||
}
|
||||
|
||||
function getInstanceDecorator (name) {
|
||||
if (!checkExistence(this, name)) {
|
||||
throw new FST_ERR_DEC_UNDECLARED(name, 'instance')
|
||||
}
|
||||
|
||||
if (typeof this[name] === 'function') {
|
||||
return this[name].bind(this)
|
||||
}
|
||||
|
||||
return this[name]
|
||||
}
|
||||
|
||||
function decorateConstructor (konstructor, name, fn, dependencies) {
|
||||
const instance = konstructor.prototype
|
||||
if (Object.prototype.hasOwnProperty.call(instance, name) || hasKey(konstructor, name)) {
|
||||
if (Object.hasOwn(instance, name) || hasKey(konstructor, name)) {
|
||||
throw new FST_ERR_DEC_ALREADY_PRESENT(name)
|
||||
}
|
||||
|
||||
@@ -58,7 +68,7 @@ function decorateConstructor (konstructor, name, fn, dependencies) {
|
||||
|
||||
function checkReferenceType (name, fn) {
|
||||
if (typeof fn === 'object' && fn && !(typeof fn.getter === 'function' || typeof fn.setter === 'function')) {
|
||||
FSTDEP006(name)
|
||||
throw new FST_ERR_DEC_REFERENCE_TYPE(name, typeof fn)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,8 +112,7 @@ function checkDependencies (instance, name, deps) {
|
||||
throw new FST_ERR_DEC_DEPENDENCY_INVALID_TYPE(name)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
for (var i = 0; i !== deps.length; ++i) {
|
||||
for (let i = 0; i !== deps.length; ++i) {
|
||||
if (!checkExistence(instance, deps[i])) {
|
||||
throw new FST_ERR_DEC_MISSING_DEPENDENCY(deps[i])
|
||||
}
|
||||
@@ -137,5 +146,7 @@ module.exports = {
|
||||
existReply: checkReplyExistence,
|
||||
dependencies: checkDependencies,
|
||||
decorateReply,
|
||||
decorateRequest
|
||||
decorateRequest,
|
||||
getInstanceDecorator,
|
||||
hasKey
|
||||
}
|
||||
|
||||
23
backend/node_modules/fastify/lib/error-handler.js
generated
vendored
23
backend/node_modules/fastify/lib/error-handler.js
generated
vendored
@@ -1,12 +1,12 @@
|
||||
'use strict'
|
||||
|
||||
const statusCodes = require('node:http').STATUS_CODES
|
||||
const wrapThenable = require('./wrapThenable')
|
||||
const wrapThenable = require('./wrap-thenable.js')
|
||||
const { setErrorStatusCode } = require('./error-status.js')
|
||||
const {
|
||||
kReplyHeaders,
|
||||
kReplyNextErrorHandler,
|
||||
kReplyIsRunningOnErrorHook,
|
||||
kReplyHasStatusCode,
|
||||
kRouteContext,
|
||||
kDisableRequestLogging
|
||||
} = require('./symbols.js')
|
||||
@@ -39,7 +39,7 @@ function handleError (reply, error, cb) {
|
||||
if (!reply.log[kDisableRequestLogging]) {
|
||||
reply.log.warn(
|
||||
{ req: reply.request, res: reply, err: error },
|
||||
error && error.message
|
||||
error?.message
|
||||
)
|
||||
}
|
||||
reply.raw.writeHead(reply.raw.statusCode)
|
||||
@@ -81,22 +81,19 @@ function handleError (reply, error, cb) {
|
||||
|
||||
function defaultErrorHandler (error, request, reply) {
|
||||
setErrorHeaders(error, reply)
|
||||
if (!reply[kReplyHasStatusCode] || reply.statusCode === 200) {
|
||||
const statusCode = error.statusCode || error.status
|
||||
reply.code(statusCode >= 400 ? statusCode : 500)
|
||||
}
|
||||
setErrorStatusCode(reply, error)
|
||||
if (reply.statusCode < 500) {
|
||||
if (!reply.log[kDisableRequestLogging]) {
|
||||
reply.log.info(
|
||||
{ res: reply, err: error },
|
||||
error && error.message
|
||||
error?.message
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if (!reply.log[kDisableRequestLogging]) {
|
||||
reply.log.error(
|
||||
{ req: request, res: reply, err: error },
|
||||
error && error.message
|
||||
error?.message
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -110,18 +107,20 @@ function fallbackErrorHandler (error, reply, cb) {
|
||||
let payload
|
||||
try {
|
||||
const serializerFn = getSchemaSerializer(reply[kRouteContext], statusCode, reply[kReplyHeaders]['content-type'])
|
||||
payload = (serializerFn === false)
|
||||
? serializeError({
|
||||
if (serializerFn === false) {
|
||||
payload = serializeError({
|
||||
error: statusCodes[statusCode + ''],
|
||||
code: error.code,
|
||||
message: error.message,
|
||||
statusCode
|
||||
})
|
||||
: serializerFn(Object.create(error, {
|
||||
} else {
|
||||
payload = serializerFn(Object.create(error, {
|
||||
error: { value: statusCodes[statusCode + ''] },
|
||||
message: { value: error.message },
|
||||
statusCode: { value: statusCode }
|
||||
}))
|
||||
}
|
||||
} catch (err) {
|
||||
if (!reply.log[kDisableRequestLogging]) {
|
||||
// error is always FST_ERR_SCH_SERIALIZATION_BUILD because this is called from route/compileSchemasForSerialization
|
||||
|
||||
3
backend/node_modules/fastify/lib/error-serializer.js
generated
vendored
3
backend/node_modules/fastify/lib/error-serializer.js
generated
vendored
@@ -1,5 +1,5 @@
|
||||
// This file is autogenerated by build/build-error-serializer.js, do not edit
|
||||
/* istanbul ignore file */
|
||||
/* c8 ignore start */
|
||||
|
||||
'use strict'
|
||||
|
||||
@@ -117,3 +117,4 @@ let addComma = false
|
||||
return main
|
||||
|
||||
}(validator, serializer)
|
||||
/* c8 ignore stop */
|
||||
|
||||
14
backend/node_modules/fastify/lib/error-status.js
generated
vendored
Normal file
14
backend/node_modules/fastify/lib/error-status.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
'use strict'
|
||||
|
||||
const {
|
||||
kReplyHasStatusCode
|
||||
} = require('./symbols')
|
||||
|
||||
function setErrorStatusCode (reply, err) {
|
||||
if (!reply[kReplyHasStatusCode] || reply.statusCode === 200) {
|
||||
const statusCode = err && (err.statusCode || err.status)
|
||||
reply.code(statusCode >= 400 ? statusCode : 500)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { setErrorStatusCode }
|
||||
72
backend/node_modules/fastify/lib/errors.js
generated
vendored
72
backend/node_modules/fastify/lib/errors.js
generated
vendored
@@ -47,12 +47,6 @@ const codes = {
|
||||
500,
|
||||
TypeError
|
||||
),
|
||||
FST_ERR_VERSION_CONSTRAINT_NOT_STR: createError(
|
||||
'FST_ERR_VERSION_CONSTRAINT_NOT_STR',
|
||||
'Version constraint should be a string.',
|
||||
500,
|
||||
TypeError
|
||||
),
|
||||
FST_ERR_VALIDATION: createError(
|
||||
'FST_ERR_VALIDATION',
|
||||
'%s',
|
||||
@@ -70,6 +64,12 @@ const codes = {
|
||||
500,
|
||||
TypeError
|
||||
),
|
||||
FST_ERR_ERROR_HANDLER_ALREADY_SET: createError(
|
||||
'FST_ERR_ERROR_HANDLER_ALREADY_SET',
|
||||
"Error Handler already set in this scope. Set 'allowErrorHandlerOverride: true' to allow overriding.",
|
||||
500,
|
||||
TypeError
|
||||
),
|
||||
|
||||
/**
|
||||
* ContentTypeParser
|
||||
@@ -124,6 +124,11 @@ const codes = {
|
||||
"Body cannot be empty when content-type is set to 'application/json'",
|
||||
400
|
||||
),
|
||||
FST_ERR_CTP_INVALID_JSON_BODY: createError(
|
||||
'FST_ERR_CTP_INVALID_JSON_BODY',
|
||||
"Body is not valid JSON but content-type is set to 'application/json'",
|
||||
400
|
||||
),
|
||||
FST_ERR_CTP_INSTANCE_ALREADY_STARTED: createError(
|
||||
'FST_ERR_CTP_INSTANCE_ALREADY_STARTED',
|
||||
'Cannot call "%s" when fastify instance is already started!',
|
||||
@@ -151,6 +156,14 @@ const codes = {
|
||||
'FST_ERR_DEC_AFTER_START',
|
||||
"The decorator '%s' has been added after start!"
|
||||
),
|
||||
FST_ERR_DEC_REFERENCE_TYPE: createError(
|
||||
'FST_ERR_DEC_REFERENCE_TYPE',
|
||||
"The decorator '%s' of type '%s' is a reference type. Use the { getter, setter } interface instead."
|
||||
),
|
||||
FST_ERR_DEC_UNDECLARED: createError(
|
||||
'FST_ERR_DEC_UNDECLARED',
|
||||
"No decorator '%s' has been declared on %s."
|
||||
),
|
||||
|
||||
/**
|
||||
* hooks
|
||||
@@ -191,7 +204,7 @@ const codes = {
|
||||
|
||||
FST_ERR_HOOK_TIMEOUT: createError(
|
||||
'FST_ERR_HOOK_TIMEOUT',
|
||||
"A callback for '%s' hook timed out. You may have forgotten to call 'done' function or to resolve a Promise"
|
||||
"A callback for '%s' hook%s timed out. You may have forgotten to call 'done' function or to resolve a Promise"
|
||||
),
|
||||
|
||||
/**
|
||||
@@ -209,6 +222,27 @@ const codes = {
|
||||
TypeError
|
||||
),
|
||||
|
||||
FST_ERR_LOG_INVALID_LOGGER_INSTANCE: createError(
|
||||
'FST_ERR_LOG_INVALID_LOGGER_INSTANCE',
|
||||
'loggerInstance only accepts a logger instance.',
|
||||
500,
|
||||
TypeError
|
||||
),
|
||||
|
||||
FST_ERR_LOG_INVALID_LOGGER_CONFIG: createError(
|
||||
'FST_ERR_LOG_INVALID_LOGGER_CONFIG',
|
||||
'logger options only accepts a configuration object.',
|
||||
500,
|
||||
TypeError
|
||||
),
|
||||
|
||||
FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED: createError(
|
||||
'FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED',
|
||||
'You cannot provide both logger and loggerInstance. Please provide only one.',
|
||||
500,
|
||||
TypeError
|
||||
),
|
||||
|
||||
/**
|
||||
* reply
|
||||
*/
|
||||
@@ -222,6 +256,10 @@ const codes = {
|
||||
'FST_ERR_REP_RESPONSE_BODY_CONSUMED',
|
||||
'Response.body is already consumed.'
|
||||
),
|
||||
FST_ERR_REP_READABLE_STREAM_LOCKED: createError(
|
||||
'FST_ERR_REP_READABLE_STREAM_LOCKED',
|
||||
'ReadableStream was locked. You should call releaseLock() method on reader before sending.'
|
||||
),
|
||||
FST_ERR_REP_ALREADY_SENT: createError(
|
||||
'FST_ERR_REP_ALREADY_SENT',
|
||||
'Reply was already sent, did you forget to "return reply" in "%s" (%s)?'
|
||||
@@ -301,14 +339,6 @@ const codes = {
|
||||
'response schemas should be nested under a valid status code, e.g { 2xx: { type: "object" } }'
|
||||
),
|
||||
|
||||
/**
|
||||
* http2
|
||||
*/
|
||||
FST_ERR_HTTP2_INVALID_VERSION: createError(
|
||||
'FST_ERR_HTTP2_INVALID_VERSION',
|
||||
'HTTP2 is available only from node >= 8.8.1'
|
||||
),
|
||||
|
||||
/**
|
||||
* initialConfig
|
||||
*/
|
||||
@@ -339,12 +369,6 @@ const codes = {
|
||||
'Unexpected error from async constraint',
|
||||
500
|
||||
),
|
||||
FST_ERR_DEFAULT_ROUTE_INVALID_TYPE: createError(
|
||||
'FST_ERR_DEFAULT_ROUTE_INVALID_TYPE',
|
||||
'The defaultRoute type should be a function',
|
||||
500,
|
||||
TypeError
|
||||
),
|
||||
FST_ERR_INVALID_URL: createError(
|
||||
'FST_ERR_INVALID_URL',
|
||||
"URL must be a string. Received '%s'",
|
||||
@@ -429,6 +453,12 @@ const codes = {
|
||||
'FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE',
|
||||
"The decorator '%s'%s is not present in %s"
|
||||
),
|
||||
FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER: createError(
|
||||
'FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER',
|
||||
'The %s plugin being registered mixes async and callback styles. Async plugin should not mix async and callback style.',
|
||||
500,
|
||||
TypeError
|
||||
),
|
||||
|
||||
/**
|
||||
* Avvio Errors
|
||||
|
||||
@@ -18,8 +18,8 @@ const { buildErrorHandler } = require('./error-handler.js')
|
||||
const {
|
||||
FST_ERR_NOT_FOUND
|
||||
} = require('./errors')
|
||||
const { createChildLogger } = require('./logger')
|
||||
const { getGenReqId } = require('./reqIdGenFactory.js')
|
||||
const { createChildLogger } = require('./logger-factory')
|
||||
const { getGenReqId } = require('./req-id-gen-factory.js')
|
||||
|
||||
/**
|
||||
* Each fastify instance have a:
|
||||
@@ -49,7 +49,8 @@ function fourOhFour (options) {
|
||||
function basic404 (request, reply) {
|
||||
const { url, method } = request.raw
|
||||
const message = `Route ${method}:${url} not found`
|
||||
if (!disableRequestLogging) {
|
||||
const resolvedDisableRequestLogging = typeof disableRequestLogging === 'function' ? disableRequestLogging(request.raw) : disableRequestLogging
|
||||
if (!resolvedDisableRequestLogging) {
|
||||
request.log.info(message)
|
||||
}
|
||||
reply.code(404).send({
|
||||
@@ -150,7 +151,9 @@ function fourOhFour (options) {
|
||||
.map(h => h.bind(this))
|
||||
context[hook] = toSet.length ? toSet : null
|
||||
}
|
||||
context.errorHandler = opts.errorHandler ? buildErrorHandler(this[kErrorHandler], opts.errorHandler) : this[kErrorHandler]
|
||||
context.errorHandler = opts.errorHandler
|
||||
? buildErrorHandler(this[kErrorHandler], opts.errorHandler)
|
||||
: this[kErrorHandler]
|
||||
})
|
||||
|
||||
if (this[kFourOhFourContext] !== null && prefix === '/') {
|
||||
187
backend/node_modules/fastify/lib/handle-request.js
generated
vendored
Normal file
187
backend/node_modules/fastify/lib/handle-request.js
generated
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
'use strict'
|
||||
|
||||
const diagnostics = require('node:diagnostics_channel')
|
||||
const { validate: validateSchema } = require('./validation')
|
||||
const { preValidationHookRunner, preHandlerHookRunner } = require('./hooks')
|
||||
const wrapThenable = require('./wrap-thenable')
|
||||
const { setErrorStatusCode } = require('./error-status')
|
||||
const {
|
||||
kReplyIsError,
|
||||
kRouteContext,
|
||||
kFourOhFourContext,
|
||||
kSupportedHTTPMethods
|
||||
} = require('./symbols')
|
||||
|
||||
const channels = diagnostics.tracingChannel('fastify.request.handler')
|
||||
|
||||
function handleRequest (err, request, reply) {
|
||||
if (reply.sent === true) return
|
||||
if (err != null) {
|
||||
reply[kReplyIsError] = true
|
||||
reply.send(err)
|
||||
return
|
||||
}
|
||||
|
||||
const method = request.method
|
||||
|
||||
if (this[kSupportedHTTPMethods].bodyless.has(method)) {
|
||||
handler(request, reply)
|
||||
return
|
||||
}
|
||||
|
||||
if (this[kSupportedHTTPMethods].bodywith.has(method)) {
|
||||
const headers = request.headers
|
||||
const contentType = headers['content-type']
|
||||
|
||||
if (contentType === undefined) {
|
||||
const contentLength = headers['content-length']
|
||||
const transferEncoding = headers['transfer-encoding']
|
||||
const isEmptyBody = transferEncoding === undefined &&
|
||||
(contentLength === undefined || contentLength === '0')
|
||||
|
||||
if (isEmptyBody) {
|
||||
// Request has no body to parse
|
||||
handler(request, reply)
|
||||
return
|
||||
}
|
||||
|
||||
request[kRouteContext].contentTypeParser.run('', handler, request, reply)
|
||||
return
|
||||
}
|
||||
|
||||
request[kRouteContext].contentTypeParser.run(contentType, handler, request, reply)
|
||||
return
|
||||
}
|
||||
|
||||
// Return 404 instead of 405 see https://github.com/fastify/fastify/pull/862 for discussion
|
||||
handler(request, reply)
|
||||
}
|
||||
|
||||
function handler (request, reply) {
|
||||
try {
|
||||
if (request[kRouteContext].preValidation !== null) {
|
||||
preValidationHookRunner(
|
||||
request[kRouteContext].preValidation,
|
||||
request,
|
||||
reply,
|
||||
preValidationCallback
|
||||
)
|
||||
} else {
|
||||
preValidationCallback(null, request, reply)
|
||||
}
|
||||
} catch (err) {
|
||||
preValidationCallback(err, request, reply)
|
||||
}
|
||||
}
|
||||
|
||||
function preValidationCallback (err, request, reply) {
|
||||
if (reply.sent === true) return
|
||||
|
||||
if (err != null) {
|
||||
reply[kReplyIsError] = true
|
||||
reply.send(err)
|
||||
return
|
||||
}
|
||||
|
||||
const validationErr = validateSchema(reply[kRouteContext], request)
|
||||
const isAsync = (validationErr && typeof validationErr.then === 'function') || false
|
||||
|
||||
if (isAsync) {
|
||||
const cb = validationCompleted.bind(null, request, reply)
|
||||
validationErr.then(cb, cb)
|
||||
} else {
|
||||
validationCompleted(request, reply, validationErr)
|
||||
}
|
||||
}
|
||||
|
||||
function validationCompleted (request, reply, validationErr) {
|
||||
if (validationErr) {
|
||||
if (reply[kRouteContext].attachValidation === false) {
|
||||
reply.send(validationErr)
|
||||
return
|
||||
}
|
||||
|
||||
reply.request.validationError = validationErr
|
||||
}
|
||||
|
||||
// preHandler hook
|
||||
if (request[kRouteContext].preHandler !== null) {
|
||||
preHandlerHookRunner(
|
||||
request[kRouteContext].preHandler,
|
||||
request,
|
||||
reply,
|
||||
preHandlerCallback
|
||||
)
|
||||
} else {
|
||||
preHandlerCallback(null, request, reply)
|
||||
}
|
||||
}
|
||||
|
||||
function preHandlerCallback (err, request, reply) {
|
||||
if (reply.sent) return
|
||||
|
||||
const context = request[kRouteContext]
|
||||
|
||||
if (!channels.hasSubscribers || context[kFourOhFourContext] === null) {
|
||||
preHandlerCallbackInner(err, request, reply)
|
||||
} else {
|
||||
const store = {
|
||||
request,
|
||||
reply,
|
||||
async: false,
|
||||
route: {
|
||||
url: context.config.url,
|
||||
method: context.config.method
|
||||
}
|
||||
}
|
||||
channels.start.runStores(store, preHandlerCallbackInner, undefined, err, request, reply, store)
|
||||
}
|
||||
}
|
||||
|
||||
function preHandlerCallbackInner (err, request, reply, store) {
|
||||
const context = request[kRouteContext]
|
||||
|
||||
try {
|
||||
if (err != null) {
|
||||
reply[kReplyIsError] = true
|
||||
if (store) {
|
||||
store.error = err
|
||||
// Set status code before publishing so subscribers see the correct value
|
||||
setErrorStatusCode(reply, err)
|
||||
channels.error.publish(store)
|
||||
}
|
||||
reply.send(err)
|
||||
return
|
||||
}
|
||||
|
||||
let result
|
||||
|
||||
try {
|
||||
result = context.handler(request, reply)
|
||||
} catch (err) {
|
||||
if (store) {
|
||||
store.error = err
|
||||
// Set status code before publishing so subscribers see the correct value
|
||||
setErrorStatusCode(reply, err)
|
||||
channels.error.publish(store)
|
||||
}
|
||||
|
||||
reply[kReplyIsError] = true
|
||||
reply.send(err)
|
||||
return
|
||||
}
|
||||
|
||||
if (result !== undefined) {
|
||||
if (result !== null && typeof result.then === 'function') {
|
||||
wrapThenable(result, reply, store)
|
||||
} else {
|
||||
reply.send(result)
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (store) channels.end.publish(store)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = handleRequest
|
||||
module.exports[Symbol.for('internals')] = { handler, preHandlerCallback }
|
||||
156
backend/node_modules/fastify/lib/handleRequest.js
generated
vendored
156
backend/node_modules/fastify/lib/handleRequest.js
generated
vendored
@@ -1,156 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const { validate: validateSchema } = require('./validation')
|
||||
const { preValidationHookRunner, preHandlerHookRunner } = require('./hooks')
|
||||
const wrapThenable = require('./wrapThenable')
|
||||
const {
|
||||
kReplyIsError,
|
||||
kRouteContext
|
||||
} = require('./symbols')
|
||||
|
||||
function handleRequest (err, request, reply) {
|
||||
if (reply.sent === true) return
|
||||
if (err != null) {
|
||||
reply[kReplyIsError] = true
|
||||
reply.send(err)
|
||||
return
|
||||
}
|
||||
|
||||
const method = request.raw.method
|
||||
const headers = request.headers
|
||||
const context = request[kRouteContext]
|
||||
|
||||
if (method === 'GET' || method === 'HEAD') {
|
||||
handler(request, reply)
|
||||
return
|
||||
}
|
||||
|
||||
const contentType = headers['content-type']
|
||||
|
||||
if (method === 'POST' || method === 'PUT' || method === 'PATCH' || method === 'TRACE' || method === 'SEARCH' ||
|
||||
method === 'PROPFIND' || method === 'PROPPATCH' || method === 'LOCK' || method === 'COPY' || method === 'MOVE' ||
|
||||
method === 'MKCOL' || method === 'REPORT' || method === 'MKCALENDAR') {
|
||||
if (contentType === undefined) {
|
||||
if (
|
||||
headers['transfer-encoding'] === undefined &&
|
||||
(headers['content-length'] === '0' || headers['content-length'] === undefined)
|
||||
) { // Request has no body to parse
|
||||
handler(request, reply)
|
||||
} else {
|
||||
context.contentTypeParser.run('', handler, request, reply)
|
||||
}
|
||||
} else {
|
||||
context.contentTypeParser.run(contentType, handler, request, reply)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (method === 'OPTIONS' || method === 'DELETE') {
|
||||
if (
|
||||
contentType !== undefined &&
|
||||
(
|
||||
headers['transfer-encoding'] !== undefined ||
|
||||
headers['content-length'] !== undefined
|
||||
)
|
||||
) {
|
||||
context.contentTypeParser.run(contentType, handler, request, reply)
|
||||
} else {
|
||||
handler(request, reply)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Return 404 instead of 405 see https://github.com/fastify/fastify/pull/862 for discussion
|
||||
handler(request, reply)
|
||||
}
|
||||
|
||||
function handler (request, reply) {
|
||||
try {
|
||||
if (request[kRouteContext].preValidation !== null) {
|
||||
preValidationHookRunner(
|
||||
request[kRouteContext].preValidation,
|
||||
request,
|
||||
reply,
|
||||
preValidationCallback
|
||||
)
|
||||
} else {
|
||||
preValidationCallback(null, request, reply)
|
||||
}
|
||||
} catch (err) {
|
||||
preValidationCallback(err, request, reply)
|
||||
}
|
||||
}
|
||||
|
||||
function preValidationCallback (err, request, reply) {
|
||||
if (reply.sent === true) return
|
||||
|
||||
if (err != null) {
|
||||
reply[kReplyIsError] = true
|
||||
reply.send(err)
|
||||
return
|
||||
}
|
||||
|
||||
const validationErr = validateSchema(reply[kRouteContext], request)
|
||||
const isAsync = (validationErr && typeof validationErr.then === 'function') || false
|
||||
|
||||
if (isAsync) {
|
||||
const cb = validationCompleted.bind(null, request, reply)
|
||||
validationErr.then(cb, cb)
|
||||
} else {
|
||||
validationCompleted(request, reply, validationErr)
|
||||
}
|
||||
}
|
||||
|
||||
function validationCompleted (request, reply, validationErr) {
|
||||
if (validationErr) {
|
||||
if (reply[kRouteContext].attachValidation === false) {
|
||||
reply.send(validationErr)
|
||||
return
|
||||
}
|
||||
|
||||
reply.request.validationError = validationErr
|
||||
}
|
||||
|
||||
// preHandler hook
|
||||
if (request[kRouteContext].preHandler !== null) {
|
||||
preHandlerHookRunner(
|
||||
request[kRouteContext].preHandler,
|
||||
request,
|
||||
reply,
|
||||
preHandlerCallback
|
||||
)
|
||||
} else {
|
||||
preHandlerCallback(null, request, reply)
|
||||
}
|
||||
}
|
||||
|
||||
function preHandlerCallback (err, request, reply) {
|
||||
if (reply.sent) return
|
||||
|
||||
if (err != null) {
|
||||
reply[kReplyIsError] = true
|
||||
reply.send(err)
|
||||
return
|
||||
}
|
||||
|
||||
let result
|
||||
|
||||
try {
|
||||
result = request[kRouteContext].handler(request, reply)
|
||||
} catch (err) {
|
||||
reply[kReplyIsError] = true
|
||||
reply.send(err)
|
||||
return
|
||||
}
|
||||
|
||||
if (result !== undefined) {
|
||||
if (result !== null && typeof result.then === 'function') {
|
||||
wrapThenable(result, reply)
|
||||
} else {
|
||||
reply.send(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = handleRequest
|
||||
module.exports[Symbol.for('internals')] = { handler, preHandlerCallback }
|
||||
@@ -3,15 +3,27 @@ function headRouteOnSendHandler (req, reply, payload, done) {
|
||||
// If payload is undefined
|
||||
if (payload === undefined) {
|
||||
reply.header('content-length', '0')
|
||||
return done(null, null)
|
||||
done(null, null)
|
||||
return
|
||||
}
|
||||
|
||||
// node:stream
|
||||
if (typeof payload.resume === 'function') {
|
||||
payload.on('error', (err) => {
|
||||
reply.log.error({ err }, 'Error on Stream found for HEAD route')
|
||||
})
|
||||
payload.resume()
|
||||
return done(null, null)
|
||||
done(null, null)
|
||||
return
|
||||
}
|
||||
|
||||
// node:stream/web
|
||||
if (typeof payload.getReader === 'function') {
|
||||
payload.cancel('Stream cancelled by HEAD route').catch((err) => {
|
||||
reply.log.error({ err }, 'Error on Stream found for HEAD route')
|
||||
})
|
||||
done(null, null)
|
||||
return
|
||||
}
|
||||
|
||||
const size = '' + Buffer.byteLength(payload)
|
||||
@@ -23,7 +35,9 @@ function headRouteOnSendHandler (req, reply, payload, done) {
|
||||
|
||||
function parseHeadOnSendHandlers (onSendHandlers) {
|
||||
if (onSendHandlers == null) return headRouteOnSendHandler
|
||||
return Array.isArray(onSendHandlers) ? [...onSendHandlers, headRouteOnSendHandler] : [onSendHandlers, headRouteOnSendHandler]
|
||||
return Array.isArray(onSendHandlers)
|
||||
? [...onSendHandlers, headRouteOnSendHandler]
|
||||
: [onSendHandlers, headRouteOnSendHandler]
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
5
backend/node_modules/fastify/lib/hooks.js
generated
vendored
5
backend/node_modules/fastify/lib/hooks.js
generated
vendored
@@ -98,9 +98,12 @@ function hookRunnerApplication (hookName, boot, server, cb) {
|
||||
next()
|
||||
|
||||
function exit (err) {
|
||||
const hookFnName = hooks[i - 1]?.name
|
||||
const hookFnFragment = hookFnName ? ` "${hookFnName}"` : ''
|
||||
|
||||
if (err) {
|
||||
if (err.code === 'AVV_ERR_READY_TIMEOUT') {
|
||||
err = appendStackTrace(err, new FST_ERR_HOOK_TIMEOUT(hookName))
|
||||
err = appendStackTrace(err, new FST_ERR_HOOK_TIMEOUT(hookName, hookFnFragment))
|
||||
} else {
|
||||
err = AVVIO_ERRORS_MAP[err.code] != null
|
||||
? appendStackTrace(err, new AVVIO_ERRORS_MAP[err.code](err.message))
|
||||
|
||||
24
backend/node_modules/fastify/lib/httpMethods.js
generated
vendored
24
backend/node_modules/fastify/lib/httpMethods.js
generated
vendored
@@ -1,24 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = {
|
||||
supportedMethods: [
|
||||
'DELETE',
|
||||
'GET',
|
||||
'HEAD',
|
||||
'PATCH',
|
||||
'POST',
|
||||
'PUT',
|
||||
'OPTIONS',
|
||||
'PROPFIND',
|
||||
'PROPPATCH',
|
||||
'MKCOL',
|
||||
'COPY',
|
||||
'MOVE',
|
||||
'LOCK',
|
||||
'UNLOCK',
|
||||
'TRACE',
|
||||
'SEARCH',
|
||||
'REPORT',
|
||||
'MKCALENDAR'
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
'use strict'
|
||||
|
||||
const validate = require('./configValidator')
|
||||
const validate = require('./config-validator')
|
||||
const deepClone = require('rfdc')({ circles: true, proto: false })
|
||||
const { FST_ERR_INIT_OPTS_INVALID } = require('./errors')
|
||||
|
||||
@@ -1,105 +1,48 @@
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* Code imported from `pino-http`
|
||||
* Repo: https://github.com/pinojs/pino-http
|
||||
* License: MIT (https://raw.githubusercontent.com/pinojs/pino-http/master/LICENSE)
|
||||
*/
|
||||
|
||||
const nullLogger = require('abstract-logging')
|
||||
const pino = require('pino')
|
||||
const { serializersSym } = pino.symbols
|
||||
const {
|
||||
FST_ERR_LOG_INVALID_DESTINATION,
|
||||
FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED,
|
||||
FST_ERR_LOG_INVALID_LOGGER_CONFIG,
|
||||
FST_ERR_LOG_INVALID_LOGGER_INSTANCE,
|
||||
FST_ERR_LOG_INVALID_LOGGER
|
||||
} = require('./errors')
|
||||
|
||||
function createPinoLogger (opts) {
|
||||
if (opts.stream && opts.file) {
|
||||
throw new FST_ERR_LOG_INVALID_DESTINATION()
|
||||
} else if (opts.file) {
|
||||
// we do not have stream
|
||||
opts.stream = pino.destination(opts.file)
|
||||
delete opts.file
|
||||
/**
|
||||
* Utility for creating a child logger with the appropriate bindings, logger factory
|
||||
* and validation.
|
||||
* @param {object} context
|
||||
* @param {import('../fastify').FastifyBaseLogger} logger
|
||||
* @param {import('../fastify').RawRequestDefaultExpression<any>} req
|
||||
* @param {string} reqId
|
||||
* @param {import('../types/logger.js').ChildLoggerOptions?} loggerOpts
|
||||
*
|
||||
* @returns {object} New logger instance, inheriting all parent bindings,
|
||||
* with child bindings added.
|
||||
*/
|
||||
function createChildLogger (context, logger, req, reqId, loggerOpts) {
|
||||
const loggerBindings = {
|
||||
[context.requestIdLogLabel]: reqId
|
||||
}
|
||||
const child = context.childLoggerFactory.call(context.server, logger, loggerBindings, loggerOpts || {}, req)
|
||||
|
||||
// Optimization: bypass validation if the factory is our own default factory
|
||||
if (context.childLoggerFactory !== defaultChildLoggerFactory) {
|
||||
validateLogger(child, true) // throw if the child is not a valid logger
|
||||
}
|
||||
|
||||
const prevLogger = opts.logger
|
||||
const prevGenReqId = opts.genReqId
|
||||
let logger = null
|
||||
|
||||
if (prevLogger) {
|
||||
opts.logger = undefined
|
||||
opts.genReqId = undefined
|
||||
// we need to tap into pino internals because in v5 it supports
|
||||
// adding serializers in child loggers
|
||||
if (prevLogger[serializersSym]) {
|
||||
opts.serializers = Object.assign({}, opts.serializers, prevLogger[serializersSym])
|
||||
}
|
||||
logger = prevLogger.child({}, opts)
|
||||
opts.logger = prevLogger
|
||||
opts.genReqId = prevGenReqId
|
||||
} else {
|
||||
logger = pino(opts, opts.stream)
|
||||
}
|
||||
|
||||
return logger
|
||||
return child
|
||||
}
|
||||
|
||||
const serializers = {
|
||||
req: function asReqValue (req) {
|
||||
return {
|
||||
method: req.method,
|
||||
url: req.url,
|
||||
version: req.headers && req.headers['accept-version'],
|
||||
hostname: req.hostname,
|
||||
remoteAddress: req.ip,
|
||||
remotePort: req.socket ? req.socket.remotePort : undefined
|
||||
}
|
||||
},
|
||||
err: pino.stdSerializers.err,
|
||||
res: function asResValue (reply) {
|
||||
return {
|
||||
statusCode: reply.statusCode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function now () {
|
||||
const ts = process.hrtime()
|
||||
return (ts[0] * 1e3) + (ts[1] / 1e6)
|
||||
}
|
||||
|
||||
function createLogger (options) {
|
||||
if (!options.logger) {
|
||||
const logger = nullLogger
|
||||
logger.child = () => logger
|
||||
return { logger, hasLogger: false }
|
||||
}
|
||||
|
||||
if (validateLogger(options.logger)) {
|
||||
const logger = createPinoLogger({
|
||||
logger: options.logger,
|
||||
serializers: Object.assign({}, serializers, options.logger.serializers)
|
||||
})
|
||||
return { logger, hasLogger: true }
|
||||
}
|
||||
|
||||
const localLoggerOptions = {}
|
||||
if (Object.prototype.toString.call(options.logger) === '[object Object]') {
|
||||
Reflect.ownKeys(options.logger).forEach(prop => {
|
||||
Object.defineProperty(localLoggerOptions, prop, {
|
||||
value: options.logger[prop],
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
})
|
||||
})
|
||||
}
|
||||
localLoggerOptions.level = localLoggerOptions.level || 'info'
|
||||
localLoggerOptions.serializers = Object.assign({}, serializers, localLoggerOptions.serializers)
|
||||
options.logger = localLoggerOptions
|
||||
const logger = createPinoLogger(options.logger)
|
||||
return { logger, hasLogger: true }
|
||||
/** Default factory to create child logger instance
|
||||
*
|
||||
* @param {import('../fastify.js').FastifyBaseLogger} logger
|
||||
* @param {import('../types/logger.js').Bindings} bindings
|
||||
* @param {import('../types/logger.js').ChildLoggerOptions} opts
|
||||
*
|
||||
* @returns {import('../types/logger.js').FastifyBaseLogger}
|
||||
*/
|
||||
function defaultChildLoggerFactory (logger, bindings, opts) {
|
||||
return logger.child(bindings, opts)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -129,42 +72,65 @@ function validateLogger (logger, strict) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility for creating a child logger with the appropriate bindings, logger factory
|
||||
* and validation.
|
||||
* @param {object} context
|
||||
* @param {import('../fastify').FastifyBaseLogger} logger
|
||||
* @param {import('../fastify').RawRequestDefaultExpression<any>} req
|
||||
* @param {string} reqId
|
||||
* @param {import('../types/logger.js').ChildLoggerOptions?} loggerOpts
|
||||
*/
|
||||
function createChildLogger (context, logger, req, reqId, loggerOpts) {
|
||||
const loggerBindings = {
|
||||
[context.requestIdLogLabel]: reqId
|
||||
}
|
||||
const child = context.childLoggerFactory.call(context.server, logger, loggerBindings, loggerOpts || {}, req)
|
||||
|
||||
// Optimization: bypass validation if the factory is our own default factory
|
||||
if (context.childLoggerFactory !== defaultChildLoggerFactory) {
|
||||
validateLogger(child, true) // throw if the child is not a valid logger
|
||||
function createLogger (options) {
|
||||
if (options.logger && options.loggerInstance) {
|
||||
throw new FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED()
|
||||
}
|
||||
|
||||
return child
|
||||
if (!options.loggerInstance && !options.logger) {
|
||||
const nullLogger = require('abstract-logging')
|
||||
const logger = nullLogger
|
||||
logger.child = () => logger
|
||||
return { logger, hasLogger: false }
|
||||
}
|
||||
|
||||
const { createPinoLogger, serializers } = require('./logger-pino.js')
|
||||
|
||||
// check if the logger instance has all required properties
|
||||
if (validateLogger(options.loggerInstance)) {
|
||||
const logger = createPinoLogger({
|
||||
logger: options.loggerInstance,
|
||||
serializers: Object.assign({}, serializers, options.loggerInstance.serializers)
|
||||
})
|
||||
return { logger, hasLogger: true }
|
||||
}
|
||||
|
||||
// if a logger instance is passed to logger, throw an exception
|
||||
if (validateLogger(options.logger)) {
|
||||
throw FST_ERR_LOG_INVALID_LOGGER_CONFIG()
|
||||
}
|
||||
|
||||
if (options.loggerInstance) {
|
||||
throw FST_ERR_LOG_INVALID_LOGGER_INSTANCE()
|
||||
}
|
||||
|
||||
const localLoggerOptions = {}
|
||||
if (Object.prototype.toString.call(options.logger) === '[object Object]') {
|
||||
Reflect.ownKeys(options.logger).forEach(prop => {
|
||||
Object.defineProperty(localLoggerOptions, prop, {
|
||||
value: options.logger[prop],
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
})
|
||||
})
|
||||
}
|
||||
localLoggerOptions.level = localLoggerOptions.level || 'info'
|
||||
localLoggerOptions.serializers = Object.assign({}, serializers, localLoggerOptions.serializers)
|
||||
options.logger = localLoggerOptions
|
||||
const logger = createPinoLogger(options.logger)
|
||||
return { logger, hasLogger: true }
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('../fastify.js').FastifyBaseLogger} logger
|
||||
* @param {import('../types/logger.js').Bindings} bindings
|
||||
* @param {import('../types/logger.js').ChildLoggerOptions} opts
|
||||
*/
|
||||
function defaultChildLoggerFactory (logger, bindings, opts) {
|
||||
return logger.child(bindings, opts)
|
||||
function now () {
|
||||
const ts = process.hrtime()
|
||||
return (ts[0] * 1e3) + (ts[1] / 1e6)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createLogger,
|
||||
createChildLogger,
|
||||
defaultChildLoggerFactory,
|
||||
serializers,
|
||||
createLogger,
|
||||
validateLogger,
|
||||
now
|
||||
}
|
||||
68
backend/node_modules/fastify/lib/logger-pino.js
generated
vendored
Normal file
68
backend/node_modules/fastify/lib/logger-pino.js
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* Code imported from `pino-http`
|
||||
* Repo: https://github.com/pinojs/pino-http
|
||||
* License: MIT (https://raw.githubusercontent.com/pinojs/pino-http/master/LICENSE)
|
||||
*/
|
||||
|
||||
const pino = require('pino')
|
||||
const { serializersSym } = pino.symbols
|
||||
const {
|
||||
FST_ERR_LOG_INVALID_DESTINATION
|
||||
} = require('./errors')
|
||||
|
||||
function createPinoLogger (opts) {
|
||||
if (opts.stream && opts.file) {
|
||||
throw new FST_ERR_LOG_INVALID_DESTINATION()
|
||||
} else if (opts.file) {
|
||||
// we do not have stream
|
||||
opts.stream = pino.destination(opts.file)
|
||||
delete opts.file
|
||||
}
|
||||
|
||||
const prevLogger = opts.logger
|
||||
const prevGenReqId = opts.genReqId
|
||||
let logger = null
|
||||
|
||||
if (prevLogger) {
|
||||
opts.logger = undefined
|
||||
opts.genReqId = undefined
|
||||
// we need to tap into pino internals because in v5 it supports
|
||||
// adding serializers in child loggers
|
||||
if (prevLogger[serializersSym]) {
|
||||
opts.serializers = Object.assign({}, opts.serializers, prevLogger[serializersSym])
|
||||
}
|
||||
logger = prevLogger.child({}, opts)
|
||||
opts.logger = prevLogger
|
||||
opts.genReqId = prevGenReqId
|
||||
} else {
|
||||
logger = pino(opts, opts.stream)
|
||||
}
|
||||
|
||||
return logger
|
||||
}
|
||||
|
||||
const serializers = {
|
||||
req: function asReqValue (req) {
|
||||
return {
|
||||
method: req.method,
|
||||
url: req.url,
|
||||
version: req.headers && req.headers['accept-version'],
|
||||
host: req.host,
|
||||
remoteAddress: req.ip,
|
||||
remotePort: req.socket ? req.socket.remotePort : undefined
|
||||
}
|
||||
},
|
||||
err: pino.stdSerializers.err,
|
||||
res: function asResValue (reply) {
|
||||
return {
|
||||
statusCode: reply.statusCode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
serializers,
|
||||
createPinoLogger
|
||||
}
|
||||
@@ -12,15 +12,16 @@ const {
|
||||
kReply,
|
||||
kRequest,
|
||||
kFourOhFour,
|
||||
kPluginNameChain
|
||||
kPluginNameChain,
|
||||
kErrorHandlerAlreadySet
|
||||
} = require('./symbols.js')
|
||||
|
||||
const Reply = require('./reply')
|
||||
const Request = require('./request')
|
||||
const SchemaController = require('./schema-controller')
|
||||
const ContentTypeParser = require('./contentTypeParser')
|
||||
const ContentTypeParser = require('./content-type-parser.js')
|
||||
const { buildHooks } = require('./hooks')
|
||||
const pluginUtils = require('./pluginUtils')
|
||||
const pluginUtils = require('./plugin-utils.js')
|
||||
|
||||
// Function that runs the encapsulation magic.
|
||||
// Everything that need to be encapsulated must be handled in this function.
|
||||
@@ -57,6 +58,7 @@ module.exports = function override (old, fn, opts) {
|
||||
// Track the plugin chain since the root instance.
|
||||
// When an non-encapsulated plugin is added, the chain will be updated.
|
||||
instance[kPluginNameChain] = [fnName]
|
||||
instance[kErrorHandlerAlreadySet] = false
|
||||
|
||||
if (instance[kLogSerializers] || opts.logSerializers) {
|
||||
instance[kLogSerializers] = Object.assign(Object.create(instance[kLogSerializers]), opts.logSerializers)
|
||||
@@ -66,7 +68,7 @@ module.exports = function override (old, fn, opts) {
|
||||
instance[kFourOhFour].arrange404(instance)
|
||||
}
|
||||
|
||||
for (const hook of instance[kHooks].onRegister) hook.call(this, instance, opts)
|
||||
for (const hook of instance[kHooks].onRegister) hook.call(old, instance, opts)
|
||||
|
||||
return instance
|
||||
}
|
||||
@@ -6,12 +6,14 @@ const kRegisteredPlugins = Symbol.for('registered-plugin')
|
||||
const {
|
||||
kTestInternals
|
||||
} = require('./symbols.js')
|
||||
const { exist, existReply, existRequest } = require('./decorate')
|
||||
const { exist, existReply, existRequest } = require('./decorate.js')
|
||||
const {
|
||||
FST_ERR_PLUGIN_VERSION_MISMATCH,
|
||||
FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE
|
||||
} = require('./errors')
|
||||
const { FSTWRN002 } = require('./warnings.js')
|
||||
FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE,
|
||||
FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER
|
||||
} = require('./errors.js')
|
||||
|
||||
const rcRegex = /-(?:rc|pre|alpha).+$/u
|
||||
|
||||
function getMeta (fn) {
|
||||
return fn[Symbol.for('plugin-meta')]
|
||||
@@ -48,7 +50,7 @@ function getPluginName (func) {
|
||||
|
||||
function getFuncPreview (func) {
|
||||
// takes the first two lines of the function if nothing else works
|
||||
return func.toString().split('\n').slice(0, 2).map(s => s.trim()).join(' -- ')
|
||||
return func.toString().split('\n', 2).map(s => s.trim()).join(' -- ')
|
||||
}
|
||||
|
||||
function getDisplayName (fn) {
|
||||
@@ -106,11 +108,11 @@ function _checkDecorators (that, instance, decorators, name) {
|
||||
|
||||
function checkVersion (fn) {
|
||||
const meta = getMeta(fn)
|
||||
if (!meta) return
|
||||
if (meta?.fastify == null) return
|
||||
|
||||
const requiredVersion = meta.fastify
|
||||
|
||||
const fastifyRc = /-rc.+$/.test(this.version)
|
||||
const fastifyRc = rcRegex.test(this.version)
|
||||
if (fastifyRc === true && semver.gt(this.version, semver.coerce(requiredVersion)) === true) {
|
||||
// A Fastify release candidate phase is taking place. In order to reduce
|
||||
// the effort needed to test plugins with the RC, we allow plugins targeting
|
||||
@@ -138,7 +140,7 @@ function registerPluginName (fn) {
|
||||
|
||||
function checkPluginHealthiness (fn, pluginName) {
|
||||
if (fn.constructor.name === 'AsyncFunction' && fn.length === 3) {
|
||||
FSTWRN002(pluginName || 'anonymous')
|
||||
throw new FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER(pluginName)
|
||||
}
|
||||
}
|
||||
|
||||
23
backend/node_modules/fastify/lib/promise.js
generated
vendored
Normal file
23
backend/node_modules/fastify/lib/promise.js
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
'use strict'
|
||||
|
||||
const { kTestInternals } = require('./symbols')
|
||||
|
||||
function withResolvers () {
|
||||
let res, rej
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
res = resolve
|
||||
rej = reject
|
||||
})
|
||||
return { promise, resolve: res, reject: rej }
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
// TODO(20.x): remove when node@20 is not supported
|
||||
withResolvers: typeof Promise.withResolvers === 'function'
|
||||
? Promise.withResolvers.bind(Promise) // Promise.withResolvers must bind to itself
|
||||
/* c8 ignore next */
|
||||
: withResolvers, // Tested using the kTestInternals
|
||||
[kTestInternals]: {
|
||||
withResolvers
|
||||
}
|
||||
}
|
||||
223
backend/node_modules/fastify/lib/reply.js
generated
vendored
223
backend/node_modules/fastify/lib/reply.js
generated
vendored
@@ -1,11 +1,9 @@
|
||||
'use strict'
|
||||
|
||||
const eos = require('node:stream').finished
|
||||
const Readable = require('node:stream').Readable
|
||||
|
||||
const {
|
||||
kFourOhFourContext,
|
||||
kPublicRouteContext,
|
||||
kReplyErrorHandlerCalled,
|
||||
kReplyHijacked,
|
||||
kReplyStartTime,
|
||||
@@ -32,8 +30,8 @@ const {
|
||||
preSerializationHookRunner
|
||||
} = require('./hooks')
|
||||
|
||||
const internals = require('./handleRequest')[Symbol.for('internals')]
|
||||
const loggerUtils = require('./logger')
|
||||
const internals = require('./handle-request.js')[Symbol.for('internals')]
|
||||
const loggerUtils = require('./logger-factory')
|
||||
const now = loggerUtils.now
|
||||
const { handleError } = require('./error-handler')
|
||||
const { getSchemaSerializer } = require('./schemas')
|
||||
@@ -46,16 +44,17 @@ const CONTENT_TYPE = {
|
||||
const {
|
||||
FST_ERR_REP_INVALID_PAYLOAD_TYPE,
|
||||
FST_ERR_REP_RESPONSE_BODY_CONSUMED,
|
||||
FST_ERR_REP_READABLE_STREAM_LOCKED,
|
||||
FST_ERR_REP_ALREADY_SENT,
|
||||
FST_ERR_REP_SENT_VALUE,
|
||||
FST_ERR_SEND_INSIDE_ONERR,
|
||||
FST_ERR_BAD_STATUS_CODE,
|
||||
FST_ERR_BAD_TRAILER_NAME,
|
||||
FST_ERR_BAD_TRAILER_VALUE,
|
||||
FST_ERR_MISSING_SERIALIZATION_FN,
|
||||
FST_ERR_MISSING_CONTENTTYPE_SERIALIZATION_FN
|
||||
FST_ERR_MISSING_CONTENTTYPE_SERIALIZATION_FN,
|
||||
FST_ERR_DEC_UNDECLARED
|
||||
} = require('./errors')
|
||||
const { FSTDEP010, FSTDEP013, FSTDEP019, FSTDEP020, FSTDEP021 } = require('./warnings')
|
||||
const decorators = require('./decorate')
|
||||
|
||||
const toString = Object.prototype.toString
|
||||
|
||||
@@ -80,14 +79,6 @@ Object.defineProperties(Reply.prototype, {
|
||||
return this.request[kRouteContext]
|
||||
}
|
||||
},
|
||||
// TODO: remove once v5 is done
|
||||
// Is temporary to avoid constant conflicts between `next` and `main`
|
||||
context: {
|
||||
get () {
|
||||
FSTDEP019()
|
||||
return this.request[kRouteContext]
|
||||
}
|
||||
},
|
||||
elapsedTime: {
|
||||
get () {
|
||||
if (this[kReplyStartTime] === undefined) {
|
||||
@@ -106,20 +97,6 @@ Object.defineProperties(Reply.prototype, {
|
||||
get () {
|
||||
// We are checking whether reply was hijacked or the response has ended.
|
||||
return (this[kReplyHijacked] || this.raw.writableEnded) === true
|
||||
},
|
||||
set (value) {
|
||||
FSTDEP010()
|
||||
|
||||
if (value !== true) {
|
||||
throw new FST_ERR_REP_SENT_VALUE()
|
||||
}
|
||||
|
||||
// We throw only if sent was overwritten from Fastify
|
||||
if (this.sent && this[kReplyHijacked]) {
|
||||
throw new FST_ERR_REP_ALREADY_SENT(this.request.url, this.request.method)
|
||||
}
|
||||
|
||||
this[kReplyHijacked] = true
|
||||
}
|
||||
},
|
||||
statusCode: {
|
||||
@@ -130,29 +107,34 @@ Object.defineProperties(Reply.prototype, {
|
||||
this.code(value)
|
||||
}
|
||||
},
|
||||
[kPublicRouteContext]: {
|
||||
routeOptions: {
|
||||
get () {
|
||||
return this.request[kPublicRouteContext]
|
||||
return this.request.routeOptions
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Reply.prototype.writeEarlyHints = function (hints, callback) {
|
||||
this.raw.writeEarlyHints(hints, callback)
|
||||
return this
|
||||
}
|
||||
|
||||
Reply.prototype.hijack = function () {
|
||||
this[kReplyHijacked] = true
|
||||
return this
|
||||
}
|
||||
|
||||
Reply.prototype.send = function (payload) {
|
||||
if (this[kReplyIsRunningOnErrorHook] === true) {
|
||||
if (this[kReplyIsRunningOnErrorHook]) {
|
||||
throw new FST_ERR_SEND_INSIDE_ONERR()
|
||||
}
|
||||
|
||||
if (this.sent) {
|
||||
if (this.sent === true) {
|
||||
this.log.warn({ err: new FST_ERR_REP_ALREADY_SENT(this.request.url, this.request.method) })
|
||||
return this
|
||||
}
|
||||
|
||||
if (payload instanceof Error || this[kReplyIsError] === true) {
|
||||
if (this[kReplyIsError] || payload instanceof Error) {
|
||||
this[kReplyIsError] = false
|
||||
onErrorHook(this, payload, onSendHook)
|
||||
return this
|
||||
@@ -179,16 +161,18 @@ Reply.prototype.send = function (payload) {
|
||||
return this
|
||||
}
|
||||
|
||||
if (payload?.buffer instanceof ArrayBuffer) {
|
||||
if (hasContentType === false) {
|
||||
if (payload.buffer instanceof ArrayBuffer) {
|
||||
if (!hasContentType) {
|
||||
this[kReplyHeaders]['content-type'] = CONTENT_TYPE.OCTET
|
||||
}
|
||||
const payloadToSend = Buffer.isBuffer(payload) ? payload : Buffer.from(payload.buffer, payload.byteOffset, payload.byteLength)
|
||||
const payloadToSend = Buffer.isBuffer(payload)
|
||||
? payload
|
||||
: Buffer.from(payload.buffer, payload.byteOffset, payload.byteLength)
|
||||
onSendHook(this, payloadToSend)
|
||||
return this
|
||||
}
|
||||
|
||||
if (hasContentType === false && typeof payload === 'string') {
|
||||
if (!hasContentType && typeof payload === 'string') {
|
||||
this[kReplyHeaders]['content-type'] = CONTENT_TYPE.PLAIN
|
||||
onSendHook(this, payload)
|
||||
return this
|
||||
@@ -199,26 +183,24 @@ Reply.prototype.send = function (payload) {
|
||||
if (typeof payload !== 'string') {
|
||||
preSerializationHook(this, payload)
|
||||
return this
|
||||
} else {
|
||||
payload = this[kReplySerializer](payload)
|
||||
}
|
||||
payload = this[kReplySerializer](payload)
|
||||
|
||||
// The indexOf below also matches custom json mimetypes such as 'application/hal+json' or 'application/ld+json'
|
||||
} else if (hasContentType === false || contentType.indexOf('json') > -1) {
|
||||
if (hasContentType === false) {
|
||||
// The indexOf below also matches custom json mimetypes such as 'application/hal+json' or 'application/ld+json'
|
||||
} else if (!hasContentType || contentType.indexOf('json') !== -1) {
|
||||
if (!hasContentType) {
|
||||
this[kReplyHeaders]['content-type'] = CONTENT_TYPE.JSON
|
||||
} else {
|
||||
} else if (contentType.indexOf('charset') === -1) {
|
||||
// If user doesn't set charset, we will set charset to utf-8
|
||||
if (contentType.indexOf('charset') === -1) {
|
||||
const customContentType = contentType.trim()
|
||||
if (customContentType.endsWith(';')) {
|
||||
// custom content-type is ended with ';'
|
||||
this[kReplyHeaders]['content-type'] = `${customContentType} charset=utf-8`
|
||||
} else {
|
||||
this[kReplyHeaders]['content-type'] = `${customContentType}; charset=utf-8`
|
||||
}
|
||||
const customContentType = contentType.trim()
|
||||
if (customContentType.endsWith(';')) {
|
||||
// custom content-type is ended with ';'
|
||||
this[kReplyHeaders]['content-type'] = `${customContentType} charset=utf-8`
|
||||
} else {
|
||||
this[kReplyHeaders]['content-type'] = `${customContentType}; charset=utf-8`
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof payload !== 'string') {
|
||||
preSerializationHook(this, payload)
|
||||
return this
|
||||
@@ -232,12 +214,8 @@ Reply.prototype.send = function (payload) {
|
||||
|
||||
Reply.prototype.getHeader = function (key) {
|
||||
key = key.toLowerCase()
|
||||
const res = this.raw
|
||||
let value = this[kReplyHeaders][key]
|
||||
if (value === undefined && res.hasHeader(key)) {
|
||||
value = res.getHeader(key)
|
||||
}
|
||||
return value
|
||||
const value = this[kReplyHeaders][key]
|
||||
return value !== undefined ? value : this.raw.getHeader(key)
|
||||
}
|
||||
|
||||
Reply.prototype.getHeaders = function () {
|
||||
@@ -283,8 +261,7 @@ Reply.prototype.header = function (key, value = '') {
|
||||
|
||||
Reply.prototype.headers = function (headers) {
|
||||
const keys = Object.keys(headers)
|
||||
/* eslint-disable no-var */
|
||||
for (var i = 0; i !== keys.length; ++i) {
|
||||
for (let i = 0; i !== keys.length; ++i) {
|
||||
const key = keys[i]
|
||||
this.header(key, headers[key])
|
||||
}
|
||||
@@ -333,12 +310,12 @@ Reply.prototype.removeTrailer = function (key) {
|
||||
}
|
||||
|
||||
Reply.prototype.code = function (code) {
|
||||
const intValue = Number(code)
|
||||
if (isNaN(intValue) || intValue < 100 || intValue > 599) {
|
||||
const statusCode = +code
|
||||
if (!(statusCode >= 100 && statusCode <= 599)) {
|
||||
throw new FST_ERR_BAD_STATUS_CODE(code || String(code))
|
||||
}
|
||||
|
||||
this.raw.statusCode = intValue
|
||||
this.raw.statusCode = statusCode
|
||||
this[kReplyHasStatusCode] = true
|
||||
return this
|
||||
}
|
||||
@@ -371,13 +348,13 @@ Reply.prototype.compileSerializationSchema = function (schema, httpStatus = null
|
||||
}
|
||||
|
||||
const serializerCompiler = this[kRouteContext].serializerCompiler ||
|
||||
this.server[kSchemaController].serializerCompiler ||
|
||||
(
|
||||
// We compile the schemas if no custom serializerCompiler is provided
|
||||
// nor set
|
||||
this.server[kSchemaController].setupSerializer(this.server[kOptions]) ||
|
||||
this.server[kSchemaController].serializerCompiler
|
||||
)
|
||||
this.server[kSchemaController].serializerCompiler ||
|
||||
(
|
||||
// We compile the schemas if no custom serializerCompiler is provided
|
||||
// nor set
|
||||
this.server[kSchemaController].setupSerializer(this.server[kOptions]) ||
|
||||
this.server[kSchemaController].serializerCompiler
|
||||
)
|
||||
|
||||
const serializeFn = serializerCompiler({
|
||||
schema,
|
||||
@@ -458,13 +435,6 @@ Reply.prototype.type = function (type) {
|
||||
}
|
||||
|
||||
Reply.prototype.redirect = function (url, code) {
|
||||
if (typeof url === 'number') {
|
||||
FSTDEP021()
|
||||
const temp = code
|
||||
code = url
|
||||
url = temp
|
||||
}
|
||||
|
||||
if (!code) {
|
||||
code = this[kReplyHasStatusCode] ? this.raw.statusCode : 302
|
||||
}
|
||||
@@ -477,13 +447,6 @@ Reply.prototype.callNotFound = function () {
|
||||
return this
|
||||
}
|
||||
|
||||
// TODO: should be removed in fastify@5
|
||||
Reply.prototype.getResponseTime = function () {
|
||||
FSTDEP020()
|
||||
|
||||
return this.elapsedTime
|
||||
}
|
||||
|
||||
// Make reply a thenable, so it could be used with async/await.
|
||||
// See
|
||||
// - https://github.com/fastify/fastify/issues/1864 for the discussions
|
||||
@@ -509,6 +472,19 @@ Reply.prototype.then = function (fulfilled, rejected) {
|
||||
})
|
||||
}
|
||||
|
||||
Reply.prototype.getDecorator = function (name) {
|
||||
if (!decorators.hasKey(this, name) && !decorators.exist(this, name)) {
|
||||
throw new FST_ERR_DEC_UNDECLARED(name, 'reply')
|
||||
}
|
||||
|
||||
const decorator = this[name]
|
||||
if (typeof decorator === 'function') {
|
||||
return decorator.bind(this)
|
||||
}
|
||||
|
||||
return decorator
|
||||
}
|
||||
|
||||
function preSerializationHook (reply, payload) {
|
||||
if (reply[kRouteContext].preSerialization !== null) {
|
||||
preSerializationHookRunner(
|
||||
@@ -519,11 +495,11 @@ function preSerializationHook (reply, payload) {
|
||||
preSerializationHookEnd
|
||||
)
|
||||
} else {
|
||||
preSerializationHookEnd(null, reply.request, reply, payload)
|
||||
preSerializationHookEnd(null, undefined, reply, payload)
|
||||
}
|
||||
}
|
||||
|
||||
function preSerializationHookEnd (err, request, reply, payload) {
|
||||
function preSerializationHookEnd (err, _request, reply, payload) {
|
||||
if (err != null) {
|
||||
onErrorHook(reply, err)
|
||||
return
|
||||
@@ -679,9 +655,9 @@ function onSendEnd (reply, payload) {
|
||||
if (reply[kReplyTrailers] === null) {
|
||||
const contentLength = reply[kReplyHeaders]['content-length']
|
||||
if (!contentLength ||
|
||||
(req.raw.method !== 'HEAD' &&
|
||||
Number(contentLength) !== Buffer.byteLength(payload)
|
||||
)
|
||||
(req.raw.method !== 'HEAD' &&
|
||||
Number(contentLength) !== Buffer.byteLength(payload)
|
||||
)
|
||||
) {
|
||||
reply[kReplyHeaders]['content-length'] = '' + Buffer.byteLength(payload)
|
||||
}
|
||||
@@ -705,8 +681,62 @@ function logStreamError (logger, err, res) {
|
||||
}
|
||||
|
||||
function sendWebStream (payload, res, reply) {
|
||||
const nodeStream = Readable.fromWeb(payload)
|
||||
sendStream(nodeStream, res, reply)
|
||||
if (payload.locked) {
|
||||
throw new FST_ERR_REP_READABLE_STREAM_LOCKED()
|
||||
}
|
||||
|
||||
let sourceOpen = true
|
||||
let errorLogged = false
|
||||
const reader = payload.getReader()
|
||||
|
||||
eos(res, function (err) {
|
||||
if (sourceOpen) {
|
||||
if (err != null && res.headersSent && !errorLogged) {
|
||||
errorLogged = true
|
||||
logStreamError(reply.log, err, res)
|
||||
}
|
||||
reader.cancel().catch(noop)
|
||||
}
|
||||
})
|
||||
|
||||
if (!res.headersSent) {
|
||||
for (const key in reply[kReplyHeaders]) {
|
||||
res.setHeader(key, reply[kReplyHeaders][key])
|
||||
}
|
||||
} else {
|
||||
reply.log.warn('response will send, but you shouldn\'t use res.writeHead in stream mode')
|
||||
}
|
||||
|
||||
function onRead (result) {
|
||||
if (result.done) {
|
||||
sourceOpen = false
|
||||
sendTrailer(null, res, reply)
|
||||
return
|
||||
}
|
||||
/* c8 ignore next 5 - race condition: eos handler typically fires first */
|
||||
if (res.destroyed) {
|
||||
sourceOpen = false
|
||||
reader.cancel().catch(noop)
|
||||
return
|
||||
}
|
||||
res.write(result.value)
|
||||
reader.read().then(onRead, onReadError)
|
||||
}
|
||||
|
||||
function onReadError (err) {
|
||||
sourceOpen = false
|
||||
if (res.headersSent || reply.request.raw.aborted === true) {
|
||||
if (!errorLogged) {
|
||||
errorLogged = true
|
||||
logStreamError(reply.log, err, reply)
|
||||
}
|
||||
res.destroy()
|
||||
} else {
|
||||
onErrorHook(reply, err)
|
||||
}
|
||||
}
|
||||
|
||||
reader.read().then(onRead, onReadError)
|
||||
}
|
||||
|
||||
function sendStream (payload, res, reply) {
|
||||
@@ -810,10 +840,6 @@ function sendTrailer (payload, res, reply) {
|
||||
const result = reply[kReplyTrailers][trailerName](reply, payload, cb)
|
||||
if (typeof result === 'object' && typeof result.then === 'function') {
|
||||
result.then((v) => cb(null, v), cb)
|
||||
} else if (result !== null && result !== undefined) {
|
||||
// TODO: should be removed in fastify@5
|
||||
FSTDEP013()
|
||||
cb(null, result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -906,10 +932,9 @@ function buildReply (R) {
|
||||
this[kReplyEndTime] = undefined
|
||||
this.log = log
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
var prop
|
||||
// eslint-disable-next-line no-var
|
||||
for (var i = 0; i < props.length; i++) {
|
||||
let prop
|
||||
|
||||
for (let i = 0; i < props.length; i++) {
|
||||
prop = props[i]
|
||||
this[prop.key] = prop.value
|
||||
}
|
||||
|
||||
168
backend/node_modules/fastify/lib/request.js
generated
vendored
168
backend/node_modules/fastify/lib/request.js
generated
vendored
@@ -1,15 +1,6 @@
|
||||
'use strict'
|
||||
|
||||
const proxyAddr = require('proxy-addr')
|
||||
const semver = require('semver')
|
||||
const {
|
||||
FSTDEP005,
|
||||
FSTDEP012,
|
||||
FSTDEP015,
|
||||
FSTDEP016,
|
||||
FSTDEP017,
|
||||
FSTDEP018
|
||||
} = require('./warnings')
|
||||
const proxyAddr = require('@fastify/proxy-addr')
|
||||
const {
|
||||
kHasBeenDecorated,
|
||||
kSchemaBody,
|
||||
@@ -20,10 +11,10 @@ const {
|
||||
kOptions,
|
||||
kRequestCacheValidateFns,
|
||||
kRouteContext,
|
||||
kPublicRouteContext,
|
||||
kRequestOriginalUrl
|
||||
} = require('./symbols')
|
||||
const { FST_ERR_REQ_INVALID_VALIDATION_INVOCATION } = require('./errors')
|
||||
const { FST_ERR_REQ_INVALID_VALIDATION_INVOCATION, FST_ERR_DEC_UNDECLARED } = require('./errors')
|
||||
const decorators = require('./decorate')
|
||||
|
||||
const HTTP_PART_SYMBOL_MAP = {
|
||||
body: kSchemaBody,
|
||||
@@ -49,8 +40,8 @@ function getTrustProxyFn (tp) {
|
||||
return tp
|
||||
}
|
||||
if (tp === true) {
|
||||
// Support plain true/false
|
||||
return function () { return true }
|
||||
// Support trusting everything
|
||||
return null
|
||||
}
|
||||
if (typeof tp === 'number') {
|
||||
// Support trusting hop count
|
||||
@@ -83,10 +74,8 @@ function buildRegularRequest (R) {
|
||||
this.log = log
|
||||
this.body = undefined
|
||||
|
||||
// eslint-disable-next-line no-var
|
||||
var prop
|
||||
// eslint-disable-next-line no-var
|
||||
for (var i = 0; i < props.length; i++) {
|
||||
let prop
|
||||
for (let i = 0; i < props.length; i++) {
|
||||
prop = props[i]
|
||||
this[prop.key] = prop.value
|
||||
}
|
||||
@@ -115,7 +104,8 @@ function buildRequestWithTrustProxy (R, trustProxy) {
|
||||
Object.defineProperties(_Request.prototype, {
|
||||
ip: {
|
||||
get () {
|
||||
return proxyAddr(this.raw, proxyFn)
|
||||
const addrs = proxyAddr.all(this.raw, proxyFn)
|
||||
return addrs[addrs.length - 1]
|
||||
}
|
||||
},
|
||||
ips: {
|
||||
@@ -123,12 +113,18 @@ function buildRequestWithTrustProxy (R, trustProxy) {
|
||||
return proxyAddr.all(this.raw, proxyFn)
|
||||
}
|
||||
},
|
||||
hostname: {
|
||||
host: {
|
||||
get () {
|
||||
if (this.ip !== undefined && this.headers['x-forwarded-host']) {
|
||||
return getLastEntryInMultiHeaderValue(this.headers['x-forwarded-host'])
|
||||
}
|
||||
return this.headers.host || this.headers[':authority']
|
||||
/**
|
||||
* The last fallback supports the following cases:
|
||||
* 1. http.requireHostHeader === false
|
||||
* 2. HTTP/1.0 without a Host Header
|
||||
* 3. Headers schema that may remove the Host Header
|
||||
*/
|
||||
return this.headers.host ?? this.headers[':authority'] ?? ''
|
||||
}
|
||||
},
|
||||
protocol: {
|
||||
@@ -146,6 +142,12 @@ function buildRequestWithTrustProxy (R, trustProxy) {
|
||||
return _Request
|
||||
}
|
||||
|
||||
function assertsRequestDecoration (request, name) {
|
||||
if (!decorators.hasKey(request, name) && !decorators.exist(request, name)) {
|
||||
throw new FST_ERR_DEC_UNDECLARED(name, 'request')
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperties(Request.prototype, {
|
||||
server: {
|
||||
get () {
|
||||
@@ -171,18 +173,6 @@ Object.defineProperties(Request.prototype, {
|
||||
return this.raw.method
|
||||
}
|
||||
},
|
||||
context: {
|
||||
get () {
|
||||
FSTDEP012()
|
||||
return this[kRouteContext]
|
||||
}
|
||||
},
|
||||
routerPath: {
|
||||
get () {
|
||||
FSTDEP017()
|
||||
return this[kRouteContext].config?.url
|
||||
}
|
||||
},
|
||||
routeOptions: {
|
||||
get () {
|
||||
const context = this[kRouteContext]
|
||||
@@ -198,37 +188,12 @@ Object.defineProperties(Request.prototype, {
|
||||
exposeHeadRoute: context.exposeHeadRoute,
|
||||
prefixTrailingSlash: context.prefixTrailingSlash,
|
||||
handler: context.handler,
|
||||
config: context.config,
|
||||
schema: context.schema,
|
||||
version
|
||||
}
|
||||
|
||||
Object.defineProperties(options, {
|
||||
config: {
|
||||
get: () => context.config
|
||||
},
|
||||
schema: {
|
||||
get: () => context.schema
|
||||
}
|
||||
})
|
||||
|
||||
return Object.freeze(options)
|
||||
}
|
||||
},
|
||||
routerMethod: {
|
||||
get () {
|
||||
FSTDEP018()
|
||||
return this[kRouteContext].config?.method
|
||||
}
|
||||
},
|
||||
routeConfig: {
|
||||
get () {
|
||||
FSTDEP016()
|
||||
return this[kRouteContext][kPublicRouteContext]?.config
|
||||
}
|
||||
},
|
||||
routeSchema: {
|
||||
get () {
|
||||
FSTDEP015()
|
||||
return this[kRouteContext][kPublicRouteContext].schema
|
||||
return options
|
||||
}
|
||||
},
|
||||
is404: {
|
||||
@@ -236,15 +201,6 @@ Object.defineProperties(Request.prototype, {
|
||||
return this[kRouteContext].config?.url === undefined
|
||||
}
|
||||
},
|
||||
connection: {
|
||||
get () {
|
||||
/* istanbul ignore next */
|
||||
if (semver.gte(process.versions.node, '13.0.0')) {
|
||||
FSTDEP005()
|
||||
}
|
||||
return this.raw.connection
|
||||
}
|
||||
},
|
||||
socket: {
|
||||
get () {
|
||||
return this.raw.socket
|
||||
@@ -257,9 +213,42 @@ Object.defineProperties(Request.prototype, {
|
||||
}
|
||||
}
|
||||
},
|
||||
host: {
|
||||
get () {
|
||||
/**
|
||||
* The last fallback supports the following cases:
|
||||
* 1. http.requireHostHeader === false
|
||||
* 2. HTTP/1.0 without a Host Header
|
||||
* 3. Headers schema that may remove the Host Header
|
||||
*/
|
||||
return this.raw.headers.host ?? this.raw.headers[':authority'] ?? ''
|
||||
}
|
||||
},
|
||||
hostname: {
|
||||
get () {
|
||||
return this.raw.headers.host || this.raw.headers[':authority']
|
||||
// Check for IPV6 Host
|
||||
if (this.host[0] === '[') {
|
||||
return this.host.slice(0, this.host.indexOf(']') + 1)
|
||||
}
|
||||
|
||||
return this.host.split(':', 1)[0]
|
||||
}
|
||||
},
|
||||
port: {
|
||||
get () {
|
||||
// first try taking port from host
|
||||
const portFromHost = parseInt(this.host.split(':').slice(-1)[0])
|
||||
if (!isNaN(portFromHost)) {
|
||||
return portFromHost
|
||||
}
|
||||
// now fall back to port from host/:authority header
|
||||
const host = (this.headers.host ?? this.headers[':authority'] ?? '')
|
||||
const portFromHeader = parseInt(host.split(':').slice(-1)[0])
|
||||
if (!isNaN(portFromHeader)) {
|
||||
return portFromHeader
|
||||
}
|
||||
// fall back to null
|
||||
return null
|
||||
}
|
||||
},
|
||||
protocol: {
|
||||
@@ -299,13 +288,13 @@ Object.defineProperties(Request.prototype, {
|
||||
}
|
||||
|
||||
const validatorCompiler = this[kRouteContext].validatorCompiler ||
|
||||
this.server[kSchemaController].validatorCompiler ||
|
||||
(
|
||||
// We compile the schemas if no custom validatorCompiler is provided
|
||||
// nor set
|
||||
this.server[kSchemaController].setupValidator(this.server[kOptions]) ||
|
||||
this.server[kSchemaController].validatorCompiler
|
||||
)
|
||||
this.server[kSchemaController].validatorCompiler ||
|
||||
(
|
||||
// We compile the schemas if no custom validatorCompiler is provided
|
||||
// nor set
|
||||
this.server[kSchemaController].setupValidator(this.server[kOptions]) ||
|
||||
this.server[kSchemaController].validatorCompiler
|
||||
)
|
||||
|
||||
const validateFn = validatorCompiler({
|
||||
schema,
|
||||
@@ -342,8 +331,8 @@ Object.defineProperties(Request.prototype, {
|
||||
|
||||
// We cannot compile if the schema is missed
|
||||
if (validate == null && (schema == null ||
|
||||
typeof schema !== 'object' ||
|
||||
Array.isArray(schema))
|
||||
typeof schema !== 'object' ||
|
||||
Array.isArray(schema))
|
||||
) {
|
||||
throw new FST_ERR_REQ_INVALID_VALIDATION_INVOCATION(httpPart)
|
||||
}
|
||||
@@ -359,6 +348,25 @@ Object.defineProperties(Request.prototype, {
|
||||
|
||||
return validate(input)
|
||||
}
|
||||
},
|
||||
getDecorator: {
|
||||
value: function (name) {
|
||||
assertsRequestDecoration(this, name)
|
||||
|
||||
const decorator = this[name]
|
||||
if (typeof decorator === 'function') {
|
||||
return decorator.bind(this)
|
||||
}
|
||||
|
||||
return decorator
|
||||
}
|
||||
},
|
||||
setDecorator: {
|
||||
value: function (name, value) {
|
||||
assertsRequestDecoration(this, name)
|
||||
|
||||
this[name] = value
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
211
backend/node_modules/fastify/lib/route.js
generated
vendored
211
backend/node_modules/fastify/lib/route.js
generated
vendored
@@ -2,16 +2,10 @@
|
||||
|
||||
const FindMyWay = require('find-my-way')
|
||||
const Context = require('./context')
|
||||
const handleRequest = require('./handleRequest')
|
||||
const handleRequest = require('./handle-request.js')
|
||||
const { onRequestAbortHookRunner, lifecycleHooks, preParsingHookRunner, onTimeoutHookRunner, onRequestHookRunner } = require('./hooks')
|
||||
const { supportedMethods } = require('./httpMethods')
|
||||
const { normalizeSchema } = require('./schemas')
|
||||
const { parseHeadOnSendHandlers } = require('./headRoute')
|
||||
const {
|
||||
FSTDEP007,
|
||||
FSTDEP008,
|
||||
FSTDEP014
|
||||
} = require('./warnings')
|
||||
const { parseHeadOnSendHandlers } = require('./head-route.js')
|
||||
|
||||
const {
|
||||
compileSchemasForValidation,
|
||||
@@ -21,7 +15,6 @@ const {
|
||||
const {
|
||||
FST_ERR_SCH_VALIDATION_BUILD,
|
||||
FST_ERR_SCH_SERIALIZATION_BUILD,
|
||||
FST_ERR_DEFAULT_ROUTE_INVALID_TYPE,
|
||||
FST_ERR_DUPLICATED_ROUTE,
|
||||
FST_ERR_INVALID_URL,
|
||||
FST_ERR_HOOK_INVALID_HANDLER,
|
||||
@@ -38,6 +31,7 @@ const {
|
||||
|
||||
const {
|
||||
kRoutePrefix,
|
||||
kSupportedHTTPMethods,
|
||||
kLogLevel,
|
||||
kLogSerializers,
|
||||
kHooks,
|
||||
@@ -55,11 +49,26 @@ const {
|
||||
kRouteContext
|
||||
} = require('./symbols.js')
|
||||
const { buildErrorHandler } = require('./error-handler')
|
||||
const { createChildLogger } = require('./logger')
|
||||
const { getGenReqId } = require('./reqIdGenFactory.js')
|
||||
const { createChildLogger } = require('./logger-factory.js')
|
||||
const { getGenReqId } = require('./req-id-gen-factory.js')
|
||||
const { FSTDEP022 } = require('./warnings')
|
||||
|
||||
const routerKeys = [
|
||||
'allowUnsafeRegex',
|
||||
'buildPrettyMeta',
|
||||
'caseSensitive',
|
||||
'constraints',
|
||||
'defaultRoute',
|
||||
'ignoreDuplicateSlashes',
|
||||
'ignoreTrailingSlash',
|
||||
'maxParamLength',
|
||||
'onBadUrl',
|
||||
'querystringParser',
|
||||
'useSemicolonDelimiter'
|
||||
]
|
||||
|
||||
function buildRouting (options) {
|
||||
const router = FindMyWay(options.config)
|
||||
const router = FindMyWay(options)
|
||||
|
||||
let avvio
|
||||
let fourOhFour
|
||||
@@ -68,11 +77,11 @@ function buildRouting (options) {
|
||||
let setupResponseListeners
|
||||
let throwIfAlreadyStarted
|
||||
let disableRequestLogging
|
||||
let disableRequestLoggingFn
|
||||
let ignoreTrailingSlash
|
||||
let ignoreDuplicateSlashes
|
||||
let return503OnClosing
|
||||
let globalExposeHeadRoutes
|
||||
let validateHTTPVersion
|
||||
let keepAliveConnections
|
||||
|
||||
let closing = false
|
||||
@@ -85,35 +94,26 @@ function buildRouting (options) {
|
||||
setup (options, fastifyArgs) {
|
||||
avvio = fastifyArgs.avvio
|
||||
fourOhFour = fastifyArgs.fourOhFour
|
||||
logger = fastifyArgs.logger
|
||||
logger = options.logger
|
||||
hasLogger = fastifyArgs.hasLogger
|
||||
setupResponseListeners = fastifyArgs.setupResponseListeners
|
||||
throwIfAlreadyStarted = fastifyArgs.throwIfAlreadyStarted
|
||||
validateHTTPVersion = fastifyArgs.validateHTTPVersion
|
||||
|
||||
globalExposeHeadRoutes = options.exposeHeadRoutes
|
||||
disableRequestLogging = options.disableRequestLogging
|
||||
ignoreTrailingSlash = options.ignoreTrailingSlash
|
||||
ignoreDuplicateSlashes = options.ignoreDuplicateSlashes
|
||||
return503OnClosing = Object.prototype.hasOwnProperty.call(options, 'return503OnClosing') ? options.return503OnClosing : true
|
||||
if (typeof disableRequestLogging === 'function') {
|
||||
disableRequestLoggingFn = options.disableRequestLogging
|
||||
}
|
||||
|
||||
ignoreTrailingSlash = options.routerOptions.ignoreTrailingSlash
|
||||
ignoreDuplicateSlashes = options.routerOptions.ignoreDuplicateSlashes
|
||||
return503OnClosing = Object.hasOwn(options, 'return503OnClosing') ? options.return503OnClosing : true
|
||||
keepAliveConnections = fastifyArgs.keepAliveConnections
|
||||
},
|
||||
routing: router.lookup.bind(router), // router func to find the right handler to call
|
||||
route, // configure a route in the fastify instance
|
||||
hasRoute,
|
||||
prepareRoute,
|
||||
getDefaultRoute: function () {
|
||||
FSTDEP014()
|
||||
return router.defaultRoute
|
||||
},
|
||||
setDefaultRoute: function (defaultRoute) {
|
||||
FSTDEP014()
|
||||
if (typeof defaultRoute !== 'function') {
|
||||
throw new FST_ERR_DEFAULT_ROUTE_INVALID_TYPE()
|
||||
}
|
||||
|
||||
router.defaultRoute = defaultRoute
|
||||
},
|
||||
routeHandler,
|
||||
closeRoutes: () => { closing = true },
|
||||
printRoutes: router.prettyPrint.bind(router),
|
||||
@@ -169,10 +169,11 @@ function buildRouting (options) {
|
||||
|
||||
function hasRoute ({ options }) {
|
||||
const normalizedMethod = options.method?.toUpperCase() ?? ''
|
||||
return findRoute({
|
||||
...options,
|
||||
method: normalizedMethod
|
||||
}) !== null
|
||||
return router.hasRoute(
|
||||
normalizedMethod,
|
||||
options.url || '',
|
||||
options.constraints
|
||||
)
|
||||
}
|
||||
|
||||
function findRoute (options) {
|
||||
@@ -200,36 +201,13 @@ function buildRouting (options) {
|
||||
* @param {{ options: import('../fastify').RouteOptions, isFastify: boolean }}
|
||||
*/
|
||||
function route ({ options, isFastify }) {
|
||||
throwIfAlreadyStarted('Cannot add route!')
|
||||
|
||||
// Since we are mutating/assigning only top level props, it is fine to have a shallow copy using the spread operator
|
||||
const opts = { ...options }
|
||||
|
||||
const { exposeHeadRoute } = opts
|
||||
const hasRouteExposeHeadRouteFlag = exposeHeadRoute != null
|
||||
const shouldExposeHead = hasRouteExposeHeadRouteFlag ? exposeHeadRoute : globalExposeHeadRoutes
|
||||
|
||||
const isGetRoute = opts.method === 'GET' ||
|
||||
(Array.isArray(opts.method) && opts.method.includes('GET'))
|
||||
const isHeadRoute = opts.method === 'HEAD' ||
|
||||
(Array.isArray(opts.method) && opts.method.includes('HEAD'))
|
||||
|
||||
// we need to clone a set of initial options for HEAD route
|
||||
const headOpts = shouldExposeHead && isGetRoute ? { ...options } : null
|
||||
|
||||
throwIfAlreadyStarted('Cannot add route!')
|
||||
|
||||
const path = opts.url || opts.path || ''
|
||||
|
||||
if (Array.isArray(opts.method)) {
|
||||
// eslint-disable-next-line no-var
|
||||
for (var i = 0; i < opts.method.length; ++i) {
|
||||
opts.method[i] = normalizeAndValidateMethod(opts.method[i])
|
||||
validateSchemaBodyOption(opts.method[i], path, opts.schema)
|
||||
}
|
||||
} else {
|
||||
opts.method = normalizeAndValidateMethod(opts.method)
|
||||
validateSchemaBodyOption(opts.method, path, opts.schema)
|
||||
}
|
||||
|
||||
if (!opts.handler) {
|
||||
throw new FST_ERR_ROUTE_MISSING_HANDLER(opts.method, path)
|
||||
}
|
||||
@@ -240,6 +218,30 @@ function buildRouting (options) {
|
||||
|
||||
validateBodyLimitOption(opts.bodyLimit)
|
||||
|
||||
const shouldExposeHead = opts.exposeHeadRoute ?? globalExposeHeadRoutes
|
||||
|
||||
let isGetRoute = false
|
||||
let isHeadRoute = false
|
||||
|
||||
if (Array.isArray(opts.method)) {
|
||||
for (let i = 0; i < opts.method.length; ++i) {
|
||||
opts.method[i] = normalizeAndValidateMethod.call(this, opts.method[i])
|
||||
validateSchemaBodyOption.call(this, opts.method[i], path, opts.schema)
|
||||
|
||||
isGetRoute = opts.method.includes('GET')
|
||||
isHeadRoute = opts.method.includes('HEAD')
|
||||
}
|
||||
} else {
|
||||
opts.method = normalizeAndValidateMethod.call(this, opts.method)
|
||||
validateSchemaBodyOption.call(this, opts.method, path, opts.schema)
|
||||
|
||||
isGetRoute = opts.method === 'GET'
|
||||
isHeadRoute = opts.method === 'HEAD'
|
||||
}
|
||||
|
||||
// we need to clone a set of initial options for HEAD route
|
||||
const headOpts = shouldExposeHead && isGetRoute ? { ...options } : null
|
||||
|
||||
const prefix = this[kRoutePrefix]
|
||||
|
||||
if (path === '/' && prefix.length > 0 && opts.method !== 'HEAD') {
|
||||
@@ -347,19 +349,9 @@ function buildRouting (options) {
|
||||
isFastify
|
||||
})
|
||||
|
||||
if (opts.version) {
|
||||
FSTDEP008()
|
||||
constraints.version = opts.version
|
||||
}
|
||||
|
||||
const headHandler = router.findRoute('HEAD', opts.url, constraints)
|
||||
const hasHEADHandler = headHandler !== null
|
||||
|
||||
// remove the head route created by fastify
|
||||
if (isHeadRoute && hasHEADHandler && !context[kRouteByFastify] && headHandler.store[kRouteByFastify]) {
|
||||
router.off('HEAD', opts.url, constraints)
|
||||
}
|
||||
|
||||
try {
|
||||
router.on(opts.method, opts.url, { constraints }, routeHandler, context)
|
||||
} catch (error) {
|
||||
@@ -377,13 +369,16 @@ function buildRouting (options) {
|
||||
|
||||
this.after((notHandledErr, done) => {
|
||||
// Send context async
|
||||
context.errorHandler = opts.errorHandler ? buildErrorHandler(this[kErrorHandler], opts.errorHandler) : this[kErrorHandler]
|
||||
context.errorHandler = opts.errorHandler
|
||||
? buildErrorHandler(this[kErrorHandler], opts.errorHandler)
|
||||
: this[kErrorHandler]
|
||||
context._parserOptions.limit = opts.bodyLimit || null
|
||||
context.logLevel = opts.logLevel
|
||||
context.logSerializers = opts.logSerializers
|
||||
context.attachValidation = opts.attachValidation
|
||||
context[kReplySerializerDefault] = this[kReplySerializerDefault]
|
||||
context.schemaErrorFormatter = opts.schemaErrorFormatter || this[kSchemaErrorFormatter] || context.schemaErrorFormatter
|
||||
context.schemaErrorFormatter =
|
||||
opts.schemaErrorFormatter || this[kSchemaErrorFormatter] || context.schemaErrorFormatter
|
||||
|
||||
// Run hooks and more
|
||||
avvio.once('preReady', () => {
|
||||
@@ -407,15 +402,24 @@ function buildRouting (options) {
|
||||
fourOhFour.setContext(this, context)
|
||||
|
||||
if (opts.schema) {
|
||||
context.schema = normalizeSchema(opts, context.schema, this.initialConfig)
|
||||
context.schema = normalizeSchema(context.schema, this.initialConfig)
|
||||
|
||||
const schemaController = this[kSchemaController]
|
||||
if (!opts.validatorCompiler && (opts.schema.body || opts.schema.headers || opts.schema.querystring || opts.schema.params)) {
|
||||
const hasValidationSchema = opts.schema.body ||
|
||||
opts.schema.headers ||
|
||||
opts.schema.querystring ||
|
||||
opts.schema.params
|
||||
if (!opts.validatorCompiler && hasValidationSchema) {
|
||||
schemaController.setupValidator(this[kOptions])
|
||||
}
|
||||
try {
|
||||
const isCustom = typeof opts?.validatorCompiler === 'function' || schemaController.isCustomValidatorCompiler
|
||||
compileSchemasForValidation(context, opts.validatorCompiler || schemaController.validatorCompiler, isCustom)
|
||||
const isCustom = typeof opts?.validatorCompiler === 'function' ||
|
||||
schemaController.isCustomValidatorCompiler
|
||||
compileSchemasForValidation(
|
||||
context,
|
||||
opts.validatorCompiler || schemaController.validatorCompiler,
|
||||
isCustom
|
||||
)
|
||||
} catch (error) {
|
||||
throw new FST_ERR_SCH_VALIDATION_BUILD(opts.method, url, error.message)
|
||||
}
|
||||
@@ -440,8 +444,6 @@ function buildRouting (options) {
|
||||
if (shouldExposeHead && isGetRoute && !isHeadRoute && !hasHEADHandler) {
|
||||
const onSendHandlers = parseHeadOnSendHandlers(headOpts.onSend)
|
||||
prepareRoute.call(this, { method: 'HEAD', url: path, options: { ...headOpts, onSend: onSendHandlers }, isFastify: true })
|
||||
} else if (hasHEADHandler && exposeHeadRoute) {
|
||||
FSTDEP007()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -458,20 +460,8 @@ function buildRouting (options) {
|
||||
loggerOpts.serializers = context.logSerializers
|
||||
}
|
||||
const childLogger = createChildLogger(context, logger, req, id, loggerOpts)
|
||||
childLogger[kDisableRequestLogging] = disableRequestLogging
|
||||
|
||||
// TODO: The check here should be removed once https://github.com/nodejs/node/issues/43115 resolve in core.
|
||||
if (!validateHTTPVersion(req.httpVersion)) {
|
||||
childLogger.info({ res: { statusCode: 505 } }, 'request aborted - invalid HTTP version')
|
||||
const message = '{"error":"HTTP Version Not Supported","message":"HTTP Version Not Supported","statusCode":505}'
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': message.length
|
||||
}
|
||||
res.writeHead(505, headers)
|
||||
res.end(message)
|
||||
return
|
||||
}
|
||||
// Set initial value; will be re-evaluated after FastifyRequest is constructed if it's a function
|
||||
childLogger[kDisableRequestLogging] = disableRequestLoggingFn ? false : disableRequestLogging
|
||||
|
||||
if (closing === true) {
|
||||
/* istanbul ignore next mac, windows */
|
||||
@@ -515,7 +505,15 @@ function buildRouting (options) {
|
||||
|
||||
const request = new context.Request(id, params, req, query, childLogger, context)
|
||||
const reply = new context.Reply(res, request, childLogger)
|
||||
if (disableRequestLogging === false) {
|
||||
|
||||
// Evaluate disableRequestLogging after FastifyRequest is constructed
|
||||
// so the caller has access to decorations and customizations
|
||||
const resolvedDisableRequestLogging = disableRequestLoggingFn
|
||||
? disableRequestLoggingFn(request)
|
||||
: disableRequestLogging
|
||||
childLogger[kDisableRequestLogging] = resolvedDisableRequestLogging
|
||||
|
||||
if (resolvedDisableRequestLogging === false) {
|
||||
childLogger.info({ req: request }, 'incoming request')
|
||||
}
|
||||
|
||||
@@ -577,7 +575,8 @@ function normalizeAndValidateMethod (method) {
|
||||
throw new FST_ERR_ROUTE_METHOD_INVALID()
|
||||
}
|
||||
method = method.toUpperCase()
|
||||
if (supportedMethods.indexOf(method) === -1) {
|
||||
if (!this[kSupportedHTTPMethods].bodyless.has(method) &&
|
||||
!this[kSupportedHTTPMethods].bodywith.has(method)) {
|
||||
throw new FST_ERR_ROUTE_METHOD_NOT_SUPPORTED(method)
|
||||
}
|
||||
|
||||
@@ -585,7 +584,7 @@ function normalizeAndValidateMethod (method) {
|
||||
}
|
||||
|
||||
function validateSchemaBodyOption (method, path, schema) {
|
||||
if ((method === 'GET' || method === 'HEAD') && schema && schema.body) {
|
||||
if (this[kSupportedHTTPMethods].bodyless.has(method) && schema?.body) {
|
||||
throw new FST_ERR_ROUTE_BODY_VALIDATION_SCHEMA_NOT_SUPPORTED(method, path)
|
||||
}
|
||||
}
|
||||
@@ -608,12 +607,30 @@ function runPreParsing (err, request, reply) {
|
||||
request[kRequestPayloadStream] = request.raw
|
||||
|
||||
if (request[kRouteContext].preParsing !== null) {
|
||||
preParsingHookRunner(request[kRouteContext].preParsing, request, reply, handleRequest)
|
||||
preParsingHookRunner(request[kRouteContext].preParsing, request, reply, handleRequest.bind(request.server))
|
||||
} else {
|
||||
handleRequest(null, request, reply)
|
||||
handleRequest.call(request.server, null, request, reply)
|
||||
}
|
||||
}
|
||||
|
||||
function buildRouterOptions (options, defaultOptions) {
|
||||
const routerOptions = options.routerOptions || Object.create(null)
|
||||
|
||||
const usedDeprecatedOptions = routerKeys.filter(key => Object.hasOwn(options, key))
|
||||
|
||||
if (usedDeprecatedOptions.length > 0) {
|
||||
FSTDEP022(usedDeprecatedOptions.join(', '))
|
||||
}
|
||||
|
||||
for (const key of routerKeys) {
|
||||
if (!Object.hasOwn(routerOptions, key)) {
|
||||
routerOptions[key] = options[key] ?? defaultOptions[key]
|
||||
}
|
||||
}
|
||||
|
||||
return routerOptions
|
||||
}
|
||||
|
||||
/**
|
||||
* Used within the route handler as a `net.Socket.close` event handler.
|
||||
* The purpose is to remove a socket from the tracked sockets collection when
|
||||
@@ -625,4 +642,4 @@ function removeTrackedSocket () {
|
||||
|
||||
function noop () { }
|
||||
|
||||
module.exports = { buildRouting, validateBodyLimitOption }
|
||||
module.exports = { buildRouting, validateBodyLimitOption, buildRouterOptions }
|
||||
|
||||
4
backend/node_modules/fastify/lib/schema-controller.js
generated
vendored
4
backend/node_modules/fastify/lib/schema-controller.js
generated
vendored
@@ -1,8 +1,6 @@
|
||||
'use strict'
|
||||
|
||||
const { buildSchemas } = require('./schemas')
|
||||
const SerializerSelector = require('@fastify/fast-json-stringify-compiler')
|
||||
const ValidatorSelector = require('@fastify/ajv-compiler')
|
||||
|
||||
/**
|
||||
* Called at every fastify context that is being created.
|
||||
@@ -21,9 +19,11 @@ function buildSchemaController (parentSchemaCtrl, opts) {
|
||||
}, opts?.compilersFactory)
|
||||
|
||||
if (!compilersFactory.buildValidator) {
|
||||
const ValidatorSelector = require('@fastify/ajv-compiler')
|
||||
compilersFactory.buildValidator = ValidatorSelector()
|
||||
}
|
||||
if (!compilersFactory.buildSerializer) {
|
||||
const SerializerSelector = require('@fastify/fast-json-stringify-compiler')
|
||||
compilersFactory.buildSerializer = SerializerSelector()
|
||||
}
|
||||
|
||||
|
||||
44
backend/node_modules/fastify/lib/schemas.js
generated
vendored
44
backend/node_modules/fastify/lib/schemas.js
generated
vendored
@@ -4,9 +4,6 @@ const fastClone = require('rfdc')({ circles: false, proto: true })
|
||||
const { kSchemaVisited, kSchemaResponse } = require('./symbols')
|
||||
const kFluentSchema = Symbol.for('fluent-schema-object')
|
||||
|
||||
const {
|
||||
FSTDEP022
|
||||
} = require('./warnings')
|
||||
const {
|
||||
FST_ERR_SCH_MISSING_ID,
|
||||
FST_ERR_SCH_ALREADY_PRESENT,
|
||||
@@ -57,7 +54,7 @@ function isCustomSchemaPrototype (schema) {
|
||||
return typeof schema === 'object' && Object.getPrototypeOf(schema) !== Object.prototype
|
||||
}
|
||||
|
||||
function normalizeSchema (opts, routeSchemas, serverOptions) {
|
||||
function normalizeSchema (routeSchemas, serverOptions) {
|
||||
if (routeSchemas[kSchemaVisited]) {
|
||||
return routeSchemas
|
||||
}
|
||||
@@ -85,11 +82,9 @@ function normalizeSchema (opts, routeSchemas, serverOptions) {
|
||||
if (!contentSchema) {
|
||||
throw new FST_ERR_SCH_CONTENT_MISSING_SCHEMA(contentType)
|
||||
}
|
||||
routeSchemas.body.content[contentType].schema = getSchemaAnyway(opts.url, contentSchema, serverOptions.jsonShorthand)
|
||||
}
|
||||
continue
|
||||
}
|
||||
routeSchemas[key] = getSchemaAnyway(opts.url, schema, serverOptions.jsonShorthand)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,25 +97,15 @@ function normalizeSchema (opts, routeSchemas, serverOptions) {
|
||||
|
||||
const contentProperty = routeSchemas.response[code].content
|
||||
|
||||
let hasContentMultipleContentTypes = false
|
||||
if (contentProperty) {
|
||||
const keys = Object.keys(contentProperty)
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const mediaName = keys[i]
|
||||
if (!contentProperty[mediaName].schema) {
|
||||
if (keys.length === 1) { break }
|
||||
throw new FST_ERR_SCH_CONTENT_MISSING_SCHEMA(mediaName)
|
||||
}
|
||||
routeSchemas.response[code].content[mediaName].schema = getSchemaAnyway(opts.url, contentProperty[mediaName].schema, serverOptions.jsonShorthand)
|
||||
if (i === keys.length - 1) {
|
||||
hasContentMultipleContentTypes = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasContentMultipleContentTypes) {
|
||||
routeSchemas.response[code] = getSchemaAnyway(opts.url, routeSchemas.response[code], serverOptions.jsonShorthand)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,18 +130,6 @@ function generateFluentSchema (schema) {
|
||||
}
|
||||
}
|
||||
|
||||
function getSchemaAnyway (url, schema, jsonShorthand) {
|
||||
if (!jsonShorthand || schema.$ref || schema.oneOf || schema.allOf || schema.anyOf || schema.$merge || schema.$patch) return schema
|
||||
if (!schema.type && !schema.properties) {
|
||||
FSTDEP022(url)
|
||||
return {
|
||||
type: 'object',
|
||||
properties: schema
|
||||
}
|
||||
}
|
||||
return schema
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the right JSON schema compiled function in the request context
|
||||
* setup by the route configuration `schema.response`.
|
||||
@@ -180,6 +153,11 @@ function getSchemaSerializer (context, statusCode, contentType) {
|
||||
return responseSchemaDef[statusCode][mediaName]
|
||||
}
|
||||
|
||||
// fallback to match all media-type
|
||||
if (responseSchemaDef[statusCode]['*/*']) {
|
||||
return responseSchemaDef[statusCode]['*/*']
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
return responseSchemaDef[statusCode]
|
||||
@@ -192,6 +170,11 @@ function getSchemaSerializer (context, statusCode, contentType) {
|
||||
return responseSchemaDef[fallbackStatusCode][mediaName]
|
||||
}
|
||||
|
||||
// fallback to match all media-type
|
||||
if (responseSchemaDef[fallbackStatusCode]['*/*']) {
|
||||
return responseSchemaDef[fallbackStatusCode]['*/*']
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -204,6 +187,11 @@ function getSchemaSerializer (context, statusCode, contentType) {
|
||||
return responseSchemaDef.default[mediaName]
|
||||
}
|
||||
|
||||
// fallback to match all media-type
|
||||
if (responseSchemaDef.default['*/*']) {
|
||||
return responseSchemaDef.default['*/*']
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
426
backend/node_modules/fastify/lib/server.js
generated
vendored
426
backend/node_modules/fastify/lib/server.js
generated
vendored
@@ -2,20 +2,23 @@
|
||||
|
||||
const http = require('node:http')
|
||||
const https = require('node:https')
|
||||
const http2 = require('node:http2')
|
||||
const dns = require('node:dns')
|
||||
const os = require('node:os')
|
||||
|
||||
const { FSTDEP011 } = require('./warnings')
|
||||
const { kState, kOptions, kServerBindings } = require('./symbols')
|
||||
const { kState, kOptions, kServerBindings, kHttp2ServerSessions } = require('./symbols')
|
||||
const { FSTWRN003 } = require('./warnings')
|
||||
const { onListenHookRunner } = require('./hooks')
|
||||
const {
|
||||
FST_ERR_HTTP2_INVALID_VERSION,
|
||||
FST_ERR_REOPENED_CLOSE_SERVER,
|
||||
FST_ERR_REOPENED_SERVER,
|
||||
FST_ERR_LISTEN_OPTIONS_INVALID
|
||||
FST_ERR_LISTEN_OPTIONS_INVALID,
|
||||
FST_ERR_FORCE_CLOSE_CONNECTIONS_IDLE_NOT_AVAILABLE
|
||||
} = require('./errors')
|
||||
const noopSet = require('./noop-set')
|
||||
const PonyPromise = require('./promise')
|
||||
|
||||
module.exports.createServer = createServer
|
||||
module.exports.compileValidateHTTPVersion = compileValidateHTTPVersion
|
||||
|
||||
function defaultResolveServerListeningText (address) {
|
||||
return `Server listening at ${address}`
|
||||
@@ -25,27 +28,15 @@ function createServer (options, httpHandler) {
|
||||
const server = getServerInstance(options, httpHandler)
|
||||
|
||||
// `this` is the Fastify object
|
||||
function listen (listenOptions, ...args) {
|
||||
let cb = args.slice(-1).pop()
|
||||
// When the variadic signature deprecation is complete, the function
|
||||
// declaration should become:
|
||||
// function listen (listenOptions = { port: 0, host: 'localhost' }, cb = undefined)
|
||||
// Upon doing so, the `normalizeListenArgs` function is no longer needed,
|
||||
// and all of this preamble to feed it correctly also no longer needed.
|
||||
const firstArgType = Object.prototype.toString.call(arguments[0])
|
||||
if (arguments.length === 0) {
|
||||
listenOptions = normalizeListenArgs([])
|
||||
} else if (arguments.length > 0 && (firstArgType !== '[object Object]' && firstArgType !== '[object Function]')) {
|
||||
FSTDEP011()
|
||||
listenOptions = normalizeListenArgs(Array.from(arguments))
|
||||
cb = listenOptions.cb
|
||||
} else if (args.length > 1) {
|
||||
// `.listen(obj, a, ..., n, callback )`
|
||||
FSTDEP011()
|
||||
// Deal with `.listen(port, host, backlog, [cb])`
|
||||
const hostPath = listenOptions.path ? [listenOptions.path] : [listenOptions.port ?? 0, listenOptions.host ?? 'localhost']
|
||||
Object.assign(listenOptions, normalizeListenArgs([...hostPath, ...args]))
|
||||
} else {
|
||||
function listen (
|
||||
listenOptions = { port: 0, host: 'localhost' },
|
||||
cb = undefined
|
||||
) {
|
||||
if (typeof cb === 'function') {
|
||||
if (cb.constructor.name === 'AsyncFunction') {
|
||||
FSTWRN003('listen method')
|
||||
}
|
||||
|
||||
listenOptions.cb = cb
|
||||
}
|
||||
if (listenOptions.signal) {
|
||||
@@ -53,10 +44,14 @@ function createServer (options, httpHandler) {
|
||||
throw new FST_ERR_LISTEN_OPTIONS_INVALID('Invalid options.signal')
|
||||
}
|
||||
|
||||
if (listenOptions.signal.aborted) {
|
||||
this.close()
|
||||
// copy the current signal state
|
||||
this[kState].aborted = listenOptions.signal.aborted
|
||||
|
||||
if (this[kState].aborted) {
|
||||
return this.close()
|
||||
} else {
|
||||
const onAborted = () => {
|
||||
this[kState].aborted = true
|
||||
this.close()
|
||||
}
|
||||
listenOptions.signal.addEventListener('abort', onAborted, { once: true })
|
||||
@@ -72,7 +67,7 @@ function createServer (options, httpHandler) {
|
||||
} else {
|
||||
host = listenOptions.host
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(listenOptions, 'host') === false ||
|
||||
if (!Object.hasOwn(listenOptions, 'host') ||
|
||||
listenOptions.host == null) {
|
||||
listenOptions.host = host
|
||||
}
|
||||
@@ -110,27 +105,47 @@ function createServer (options, httpHandler) {
|
||||
|
||||
if (cb === undefined) {
|
||||
const listening = listenPromise.call(this, server, listenOptions)
|
||||
/* istanbul ignore else */
|
||||
return listening.then(address => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (host === 'localhost') {
|
||||
multipleBindings.call(this, server, httpHandler, options, listenOptions, () => {
|
||||
this[kState].listening = true
|
||||
resolve(address)
|
||||
onListenHookRunner(this)
|
||||
})
|
||||
} else {
|
||||
const { promise, resolve } = PonyPromise.withResolvers()
|
||||
if (host === 'localhost') {
|
||||
multipleBindings.call(this, server, httpHandler, options, listenOptions, () => {
|
||||
this[kState].listening = true
|
||||
resolve(address)
|
||||
onListenHookRunner(this)
|
||||
}
|
||||
})
|
||||
})
|
||||
} else {
|
||||
resolve(address)
|
||||
onListenHookRunner(this)
|
||||
}
|
||||
return promise
|
||||
})
|
||||
}
|
||||
|
||||
this.ready(listenCallback.call(this, server, listenOptions))
|
||||
}
|
||||
|
||||
return { server, listen }
|
||||
const serverHasCloseAllConnections = typeof server.closeAllConnections === 'function'
|
||||
const serverHasCloseIdleConnections = typeof server.closeIdleConnections === 'function'
|
||||
const serverHasCloseHttp2Sessions = typeof server.closeHttp2Sessions === 'function'
|
||||
|
||||
let forceCloseConnections = options.forceCloseConnections
|
||||
if (forceCloseConnections === 'idle' && !serverHasCloseIdleConnections) {
|
||||
throw new FST_ERR_FORCE_CLOSE_CONNECTIONS_IDLE_NOT_AVAILABLE()
|
||||
} else if (typeof forceCloseConnections !== 'boolean') {
|
||||
/* istanbul ignore next: only one branch can be valid in a given Node.js version */
|
||||
forceCloseConnections = serverHasCloseIdleConnections ? 'idle' : false
|
||||
}
|
||||
|
||||
const keepAliveConnections = !serverHasCloseAllConnections && forceCloseConnections === true ? new Set() : noopSet()
|
||||
|
||||
return {
|
||||
server,
|
||||
listen,
|
||||
forceCloseConnections,
|
||||
serverHasCloseAllConnections,
|
||||
serverHasCloseHttp2Sessions,
|
||||
keepAliveConnections
|
||||
}
|
||||
}
|
||||
|
||||
function multipleBindings (mainServer, httpHandler, serverOpts, listenOptions, onListen) {
|
||||
@@ -139,7 +154,7 @@ function multipleBindings (mainServer, httpHandler, serverOpts, listenOptions, o
|
||||
|
||||
// let's check if we need to bind additional addresses
|
||||
dns.lookup(listenOptions.host, { all: true }, (dnsErr, addresses) => {
|
||||
if (dnsErr) {
|
||||
if (dnsErr || this[kState].aborted) {
|
||||
// not blocking the main server listening
|
||||
// this.log.warn('dns.lookup error:', dnsErr)
|
||||
onListen()
|
||||
@@ -161,7 +176,6 @@ function multipleBindings (mainServer, httpHandler, serverOpts, listenOptions, o
|
||||
cb: (_ignoreErr) => {
|
||||
bound++
|
||||
|
||||
/* istanbul ignore next: the else won't be taken unless listening fails */
|
||||
if (!_ignoreErr) {
|
||||
this[kServerBindings].push(secondaryServer)
|
||||
}
|
||||
@@ -175,20 +189,18 @@ function multipleBindings (mainServer, httpHandler, serverOpts, listenOptions, o
|
||||
|
||||
const secondaryServer = getServerInstance(serverOpts, httpHandler)
|
||||
const closeSecondary = () => {
|
||||
// To avoid fall into situations where the close of the
|
||||
// To avoid falling into situations where the close of the
|
||||
// secondary server is triggered before the preClose hook
|
||||
// is done running, we better wait until the main server
|
||||
// is closed.
|
||||
// is done running, we better wait until the main server is closed.
|
||||
// No new TCP connections are accepted
|
||||
// We swallow any error from the secondary
|
||||
// server
|
||||
// We swallow any error from the secondary server
|
||||
secondaryServer.close(() => {})
|
||||
if (serverOpts.forceCloseConnections === 'idle') {
|
||||
// Not needed in Node 19
|
||||
secondaryServer.closeIdleConnections()
|
||||
} else if (typeof secondaryServer.closeAllConnections === 'function' && serverOpts.forceCloseConnections) {
|
||||
if (typeof secondaryServer.closeAllConnections === 'function' && serverOpts.forceCloseConnections === true) {
|
||||
secondaryServer.closeAllConnections()
|
||||
}
|
||||
if (typeof secondaryServer.closeHttp2Sessions === 'function') {
|
||||
secondaryServer.closeHttp2Sessions()
|
||||
}
|
||||
}
|
||||
|
||||
secondaryServer.on('upgrade', mainServer.emit.bind(mainServer, 'upgrade'))
|
||||
@@ -210,7 +222,6 @@ function multipleBindings (mainServer, httpHandler, serverOpts, listenOptions, o
|
||||
// to the secondary servers. It is valid only when the user is
|
||||
// listening on localhost
|
||||
const originUnref = mainServer.unref
|
||||
/* c8 ignore next 4 */
|
||||
mainServer.unref = function () {
|
||||
originUnref.call(mainServer)
|
||||
mainServer.emit('unref')
|
||||
@@ -223,7 +234,11 @@ function listenCallback (server, listenOptions) {
|
||||
server.removeListener('error', wrap)
|
||||
server.removeListener('listening', wrap)
|
||||
if (!err) {
|
||||
const address = logServerAddress.call(this, server, listenOptions.listenTextResolver || defaultResolveServerListeningText)
|
||||
const address = logServerAddress.call(
|
||||
this,
|
||||
server,
|
||||
listenOptions.listenTextResolver || defaultResolveServerListeningText
|
||||
)
|
||||
listenOptions.cb(null, address)
|
||||
} else {
|
||||
this[kState].listening = false
|
||||
@@ -236,7 +251,8 @@ function listenCallback (server, listenOptions) {
|
||||
|
||||
if (this[kState].listening && this[kState].closing) {
|
||||
return listenOptions.cb(new FST_ERR_REOPENED_CLOSE_SERVER(), null)
|
||||
} else if (this[kState].listening) {
|
||||
}
|
||||
if (this[kState].listening) {
|
||||
return listenOptions.cb(new FST_ERR_REOPENED_SERVER(), null)
|
||||
}
|
||||
|
||||
@@ -252,196 +268,174 @@ function listenCallback (server, listenOptions) {
|
||||
function listenPromise (server, listenOptions) {
|
||||
if (this[kState].listening && this[kState].closing) {
|
||||
return Promise.reject(new FST_ERR_REOPENED_CLOSE_SERVER())
|
||||
} else if (this[kState].listening) {
|
||||
}
|
||||
if (this[kState].listening) {
|
||||
return Promise.reject(new FST_ERR_REOPENED_SERVER())
|
||||
}
|
||||
|
||||
return this.ready().then(() => {
|
||||
let errEventHandler
|
||||
let listeningEventHandler
|
||||
// skip listen when aborted during ready
|
||||
if (this[kState].aborted) return
|
||||
|
||||
const { promise, resolve, reject } = PonyPromise.withResolvers()
|
||||
|
||||
const errEventHandler = (err) => {
|
||||
cleanup()
|
||||
this[kState].listening = false
|
||||
reject(err)
|
||||
}
|
||||
const listeningEventHandler = () => {
|
||||
cleanup()
|
||||
this[kState].listening = true
|
||||
resolve(logServerAddress.call(
|
||||
this,
|
||||
server,
|
||||
listenOptions.listenTextResolver || defaultResolveServerListeningText
|
||||
))
|
||||
}
|
||||
function cleanup () {
|
||||
server.removeListener('error', errEventHandler)
|
||||
server.removeListener('listening', listeningEventHandler)
|
||||
}
|
||||
const errEvent = new Promise((resolve, reject) => {
|
||||
errEventHandler = (err) => {
|
||||
cleanup()
|
||||
this[kState].listening = false
|
||||
reject(err)
|
||||
}
|
||||
server.once('error', errEventHandler)
|
||||
})
|
||||
const listeningEvent = new Promise((resolve, reject) => {
|
||||
listeningEventHandler = () => {
|
||||
cleanup()
|
||||
this[kState].listening = true
|
||||
resolve(logServerAddress.call(this, server, listenOptions.listenTextResolver || defaultResolveServerListeningText))
|
||||
}
|
||||
server.once('listening', listeningEventHandler)
|
||||
})
|
||||
server.once('error', errEventHandler)
|
||||
server.once('listening', listeningEventHandler)
|
||||
|
||||
server.listen(listenOptions)
|
||||
|
||||
return Promise.race([
|
||||
errEvent, // e.g invalid port range error is always emitted before the server listening
|
||||
listeningEvent
|
||||
])
|
||||
return promise
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function that, based upon initial configuration, will
|
||||
* verify that every incoming request conforms to allowed
|
||||
* HTTP versions for the Fastify instance, e.g. a Fastify HTTP/1.1
|
||||
* server will not serve HTTP/2 requests upon the result of the
|
||||
* verification function.
|
||||
*
|
||||
* @param {object} options fastify option
|
||||
* @param {function} [options.serverFactory] If present, the
|
||||
* validator function will skip all checks.
|
||||
* @param {boolean} [options.http2 = false] If true, the validator
|
||||
* function will allow HTTP/2 requests.
|
||||
* @param {object} [options.https = null] https server options
|
||||
* @param {boolean} [options.https.allowHTTP1] If true and use
|
||||
* with options.http2 the validator function will allow HTTP/1
|
||||
* request to http2 server.
|
||||
*
|
||||
* @returns {function} HTTP version validator function.
|
||||
*/
|
||||
function compileValidateHTTPVersion (options) {
|
||||
let bypass = false
|
||||
// key-value map to store valid http version
|
||||
const map = new Map()
|
||||
if (options.serverFactory) {
|
||||
// When serverFactory is passed, we cannot identify how to check http version reliably
|
||||
// So, we should skip the http version check
|
||||
bypass = true
|
||||
}
|
||||
if (options.http2) {
|
||||
// HTTP2 must serve HTTP/2.0
|
||||
map.set('2.0', true)
|
||||
if (options.https && options.https.allowHTTP1 === true) {
|
||||
// HTTP2 with HTTPS.allowHTTP1 allow fallback to HTTP/1.1 and HTTP/1.0
|
||||
map.set('1.1', true)
|
||||
map.set('1.0', true)
|
||||
}
|
||||
} else {
|
||||
// HTTP must server HTTP/1.1 and HTTP/1.0
|
||||
map.set('1.1', true)
|
||||
map.set('1.0', true)
|
||||
}
|
||||
// The compiled function here placed in one of the hottest path inside fastify
|
||||
// the implementation here must be as performant as possible
|
||||
return function validateHTTPVersion (httpVersion) {
|
||||
// `bypass` skip the check when custom server factory provided
|
||||
// `httpVersion in obj` check for the valid http version we should support
|
||||
return bypass || map.has(httpVersion)
|
||||
}
|
||||
}
|
||||
|
||||
function getServerInstance (options, httpHandler) {
|
||||
let server = null
|
||||
// node@20 do not accepts options as boolean
|
||||
// we need to provide proper https option
|
||||
const httpsOptions = options.https === true ? {} : options.https
|
||||
if (options.serverFactory) {
|
||||
server = options.serverFactory(httpHandler, options)
|
||||
} else if (options.http2) {
|
||||
if (typeof httpsOptions === 'object') {
|
||||
server = http2().createSecureServer(httpsOptions, httpHandler)
|
||||
} else {
|
||||
server = http2().createServer(httpHandler)
|
||||
}
|
||||
server.on('session', sessionTimeout(options.http2SessionTimeout))
|
||||
} else {
|
||||
// this is http1
|
||||
if (httpsOptions) {
|
||||
server = https.createServer(httpsOptions, httpHandler)
|
||||
} else {
|
||||
server = http.createServer(options.http, httpHandler)
|
||||
}
|
||||
server.keepAliveTimeout = options.keepAliveTimeout
|
||||
server.requestTimeout = options.requestTimeout
|
||||
// we treat zero as null
|
||||
// and null is the default setting from nodejs
|
||||
// so we do not pass the option to server
|
||||
if (options.maxRequestsPerSocket > 0) {
|
||||
server.maxRequestsPerSocket = options.maxRequestsPerSocket
|
||||
}
|
||||
// User provided server instance
|
||||
return options.serverFactory(httpHandler, options)
|
||||
}
|
||||
|
||||
if (!options.serverFactory) {
|
||||
// We have accepted true as a valid way to init https but node requires an options obj
|
||||
const httpsOptions = options.https === true ? {} : options.https
|
||||
|
||||
if (options.http2) {
|
||||
const server = typeof httpsOptions === 'object' ? http2.createSecureServer(httpsOptions, httpHandler) : http2.createServer(options.http, httpHandler)
|
||||
server.on('session', (session) => session.setTimeout(options.http2SessionTimeout, () => {
|
||||
session.close()
|
||||
}))
|
||||
|
||||
// This is only needed for Node.js versions < 24.0.0 since Node.js added native
|
||||
// closeAllSessions() on server.close() support for HTTP/2 servers in v24.0.0
|
||||
if (options.forceCloseConnections === true) {
|
||||
server.closeHttp2Sessions = createCloseHttp2SessionsByHttp2Server(server)
|
||||
}
|
||||
|
||||
server.setTimeout(options.connectionTimeout)
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
// HTTP1 server instance
|
||||
const server = httpsOptions
|
||||
? https.createServer(httpsOptions, httpHandler)
|
||||
: http.createServer(options.http, httpHandler)
|
||||
server.keepAliveTimeout = options.keepAliveTimeout
|
||||
server.requestTimeout = options.requestTimeout
|
||||
server.setTimeout(options.connectionTimeout)
|
||||
// We treat zero as null(node default) so we do not pass zero to the server instance
|
||||
if (options.maxRequestsPerSocket > 0) {
|
||||
server.maxRequestsPerSocket = options.maxRequestsPerSocket
|
||||
}
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
function normalizeListenArgs (args) {
|
||||
if (args.length === 0) {
|
||||
return { port: 0, host: 'localhost' }
|
||||
/**
|
||||
* Inspects the provided `server.address` object and returns a
|
||||
* normalized list of IP address strings. Normalization in this
|
||||
* case refers to mapping wildcard `0.0.0.0` to the list of IP
|
||||
* addresses the wildcard refers to.
|
||||
*
|
||||
* @see https://nodejs.org/docs/latest/api/net.html#serveraddress
|
||||
*
|
||||
* @param {object} A server address object as described in the
|
||||
* linked docs.
|
||||
*
|
||||
* @returns {string[]}
|
||||
*/
|
||||
function getAddresses (address) {
|
||||
if (address.address === '0.0.0.0') {
|
||||
return Object.values(os.networkInterfaces()).flatMap((iface) => {
|
||||
return iface.filter((iface) => iface.family === 'IPv4')
|
||||
}).sort((iface) => {
|
||||
/* c8 ignore next 2 */
|
||||
// Order the interfaces so that internal ones come first
|
||||
return iface.internal ? -1 : 1
|
||||
}).map((iface) => { return iface.address })
|
||||
}
|
||||
|
||||
const cb = typeof args[args.length - 1] === 'function' ? args.pop() : undefined
|
||||
const options = { cb }
|
||||
|
||||
const firstArg = args[0]
|
||||
const argsLength = args.length
|
||||
const lastArg = args[argsLength - 1]
|
||||
if (typeof firstArg === 'string' && isNaN(firstArg)) {
|
||||
/* Deal with listen (pipe[, backlog]) */
|
||||
options.path = firstArg
|
||||
options.backlog = argsLength > 1 ? lastArg : undefined
|
||||
} else {
|
||||
/* Deal with listen ([port[, host[, backlog]]]) */
|
||||
options.port = argsLength >= 1 && Number.isInteger(firstArg) ? firstArg : normalizePort(firstArg)
|
||||
// This will listen to what localhost is.
|
||||
// It can be 127.0.0.1 or ::1, depending on the operating system.
|
||||
// Fixes https://github.com/fastify/fastify/issues/1022.
|
||||
options.host = argsLength >= 2 && args[1] ? args[1] : 'localhost'
|
||||
options.backlog = argsLength >= 3 ? args[2] : undefined
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
function normalizePort (firstArg) {
|
||||
const port = Number(firstArg)
|
||||
return port >= 0 && !Number.isNaN(port) && Number.isInteger(port) ? port : 0
|
||||
return [address.address]
|
||||
}
|
||||
|
||||
function logServerAddress (server, listenTextResolver) {
|
||||
let address = server.address()
|
||||
const isUnixSocket = typeof address === 'string'
|
||||
/* istanbul ignore next */
|
||||
let addresses
|
||||
const isUnixSocket = typeof server.address() === 'string'
|
||||
if (!isUnixSocket) {
|
||||
if (address.address.indexOf(':') === -1) {
|
||||
address = address.address + ':' + address.port
|
||||
if (server.address().address.indexOf(':') === -1) {
|
||||
// IPv4
|
||||
addresses = getAddresses(server.address()).map((address) => address + ':' + server.address().port)
|
||||
} else {
|
||||
address = '[' + address.address + ']:' + address.port
|
||||
// IPv6
|
||||
addresses = ['[' + server.address().address + ']:' + server.address().port]
|
||||
}
|
||||
|
||||
addresses = addresses.map((address) => ('http' + (this[kOptions].https ? 's' : '') + '://') + address)
|
||||
} else {
|
||||
addresses = [server.address()]
|
||||
}
|
||||
|
||||
for (const address of addresses) {
|
||||
this.log.info(listenTextResolver(address))
|
||||
}
|
||||
return addresses[0]
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {http2.Http2Server} http2Server
|
||||
* @returns {() => void}
|
||||
*/
|
||||
function createCloseHttp2SessionsByHttp2Server (http2Server) {
|
||||
/**
|
||||
* @type {Set<http2.Http2Session>}
|
||||
*/
|
||||
http2Server[kHttp2ServerSessions] = new Set()
|
||||
|
||||
http2Server.on('session', function (session) {
|
||||
session.once('connect', function () {
|
||||
http2Server[kHttp2ServerSessions].add(session)
|
||||
})
|
||||
|
||||
session.once('close', function () {
|
||||
http2Server[kHttp2ServerSessions].delete(session)
|
||||
})
|
||||
|
||||
session.once('frameError', function (type, code, streamId) {
|
||||
if (streamId === 0) {
|
||||
// The stream ID is 0, which means that the error is related to the session itself.
|
||||
// If the event is not associated with a stream, the Http2Session will be shut down immediately
|
||||
http2Server[kHttp2ServerSessions].delete(session)
|
||||
}
|
||||
})
|
||||
|
||||
session.once('goaway', function () {
|
||||
// The Http2Session instance will be shut down automatically when the 'goaway' event is emitted.
|
||||
http2Server[kHttp2ServerSessions].delete(session)
|
||||
})
|
||||
})
|
||||
|
||||
return function closeHttp2Sessions () {
|
||||
if (http2Server[kHttp2ServerSessions].size === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
for (const session of http2Server[kHttp2ServerSessions]) {
|
||||
session.close()
|
||||
}
|
||||
}
|
||||
/* istanbul ignore next */
|
||||
address = (isUnixSocket ? '' : ('http' + (this[kOptions].https ? 's' : '') + '://')) + address
|
||||
|
||||
const serverListeningText = listenTextResolver(address)
|
||||
this.log.info(serverListeningText)
|
||||
return address
|
||||
}
|
||||
|
||||
function http2 () {
|
||||
try {
|
||||
return require('node:http2')
|
||||
} catch (err) {
|
||||
throw new FST_ERR_HTTP2_INVALID_VERSION()
|
||||
}
|
||||
}
|
||||
|
||||
function sessionTimeout (timeout) {
|
||||
return function (session) {
|
||||
session.setTimeout(timeout, close)
|
||||
}
|
||||
}
|
||||
|
||||
function close () {
|
||||
this.close()
|
||||
}
|
||||
|
||||
4
backend/node_modules/fastify/lib/symbols.js
generated
vendored
4
backend/node_modules/fastify/lib/symbols.js
generated
vendored
@@ -5,6 +5,7 @@ const keys = {
|
||||
kChildren: Symbol('fastify.children'),
|
||||
kServerBindings: Symbol('fastify.serverBindings'),
|
||||
kBodyLimit: Symbol('fastify.bodyLimit'),
|
||||
kSupportedHTTPMethods: Symbol('fastify.acceptedHTTPMethods'),
|
||||
kRoutePrefix: Symbol('fastify.routePrefix'),
|
||||
kLogLevel: Symbol('fastify.logLevel'),
|
||||
kLogSerializers: Symbol('fastify.logSerializers'),
|
||||
@@ -15,8 +16,8 @@ const keys = {
|
||||
kDisableRequestLogging: Symbol('fastify.disableRequestLogging'),
|
||||
kPluginNameChain: Symbol('fastify.pluginNameChain'),
|
||||
kRouteContext: Symbol('fastify.context'),
|
||||
kPublicRouteContext: Symbol('fastify.routeOptions'),
|
||||
kGenReqId: Symbol('fastify.genReqId'),
|
||||
kHttp2ServerSessions: Symbol('fastify.http2ServerSessions'),
|
||||
// Schema
|
||||
kSchemaController: Symbol('fastify.schemaController'),
|
||||
kSchemaHeaders: Symbol('headers-schema'),
|
||||
@@ -56,6 +57,7 @@ const keys = {
|
||||
// This symbol is only meant to be used for fastify tests and should not be used for any other purpose
|
||||
kTestInternals: Symbol('fastify.testInternals'),
|
||||
kErrorHandler: Symbol('fastify.errorHandler'),
|
||||
kErrorHandlerAlreadySet: Symbol('fastify.errorHandlerAlreadySet'),
|
||||
kChildLoggerFactory: Symbol('fastify.childLoggerFactory'),
|
||||
kHasBeenDecorated: Symbol('fastify.hasBeenDecorated'),
|
||||
kKeepAliveConnections: Symbol('fastify.keepAliveConnections'),
|
||||
|
||||
24
backend/node_modules/fastify/lib/validation.js
generated
vendored
24
backend/node_modules/fastify/lib/validation.js
generated
vendored
@@ -7,7 +7,7 @@ const {
|
||||
kSchemaBody: bodySchema,
|
||||
kSchemaResponse: responseSchema
|
||||
} = require('./symbols')
|
||||
const scChecker = /^[1-5]{1}[0-9]{2}$|^[1-5]xx$|^default$/
|
||||
const scChecker = /^[1-5](?:\d{2}|xx)$|^default$/
|
||||
|
||||
const {
|
||||
FST_ERR_SCH_RESPONSE_SCHEMA_NOT_NESTED_2XX
|
||||
@@ -24,7 +24,7 @@ function compileSchemasForSerialization (context, compile) {
|
||||
.reduce(function (acc, statusCode) {
|
||||
const schema = context.schema.response[statusCode]
|
||||
statusCode = statusCode.toLowerCase()
|
||||
if (!scChecker.exec(statusCode)) {
|
||||
if (!scChecker.test(statusCode)) {
|
||||
throw new FST_ERR_SCH_RESPONSE_SCHEMA_NOT_NESTED_2XX()
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ function compileSchemasForValidation (context, compile, isCustom) {
|
||||
})
|
||||
}
|
||||
context[headersSchema] = compile({ schema: headersSchemaLowerCase, method, url, httpPart: 'headers' })
|
||||
} else if (Object.prototype.hasOwnProperty.call(schema, 'headers')) {
|
||||
} else if (Object.hasOwn(schema, 'headers')) {
|
||||
FSTWRN001('headers', method, url)
|
||||
}
|
||||
|
||||
@@ -98,28 +98,36 @@ function compileSchemasForValidation (context, compile, isCustom) {
|
||||
} else {
|
||||
context[bodySchema] = compile({ schema: schema.body, method, url, httpPart: 'body' })
|
||||
}
|
||||
} else if (Object.prototype.hasOwnProperty.call(schema, 'body')) {
|
||||
} else if (Object.hasOwn(schema, 'body')) {
|
||||
FSTWRN001('body', method, url)
|
||||
}
|
||||
|
||||
if (schema.querystring) {
|
||||
context[querystringSchema] = compile({ schema: schema.querystring, method, url, httpPart: 'querystring' })
|
||||
} else if (Object.prototype.hasOwnProperty.call(schema, 'querystring')) {
|
||||
} else if (Object.hasOwn(schema, 'querystring')) {
|
||||
FSTWRN001('querystring', method, url)
|
||||
}
|
||||
|
||||
if (schema.params) {
|
||||
context[paramsSchema] = compile({ schema: schema.params, method, url, httpPart: 'params' })
|
||||
} else if (Object.prototype.hasOwnProperty.call(schema, 'params')) {
|
||||
} else if (Object.hasOwn(schema, 'params')) {
|
||||
FSTWRN001('params', method, url)
|
||||
}
|
||||
}
|
||||
|
||||
function validateParam (validatorFunction, request, paramName) {
|
||||
const isUndefined = request[paramName] === undefined
|
||||
const ret = validatorFunction && validatorFunction(isUndefined ? null : request[paramName])
|
||||
let ret
|
||||
|
||||
if (ret?.then) {
|
||||
try {
|
||||
ret = validatorFunction?.(isUndefined ? null : request[paramName])
|
||||
} catch (err) {
|
||||
// If validator throws synchronously, ensure it propagates as an internal error
|
||||
err.statusCode = 500
|
||||
return err
|
||||
}
|
||||
|
||||
if (ret && typeof ret.then === 'function') {
|
||||
return ret
|
||||
.then((res) => { return answer(res) })
|
||||
.catch(err => { return err }) // return as simple error (not throw)
|
||||
|
||||
151
backend/node_modules/fastify/lib/warnings.js
generated
vendored
151
backend/node_modules/fastify/lib/warnings.js
generated
vendored
@@ -1,96 +1,17 @@
|
||||
'use strict'
|
||||
|
||||
const { createDeprecation, createWarning } = require('process-warning')
|
||||
const { createWarning } = require('process-warning')
|
||||
|
||||
const FSTDEP005 = createDeprecation({
|
||||
code: 'FSTDEP005',
|
||||
message: 'You are accessing the deprecated "request.connection" property. Use "request.socket" instead.'
|
||||
})
|
||||
|
||||
const FSTDEP006 = createDeprecation({
|
||||
code: 'FSTDEP006',
|
||||
message: 'You are decorating Request/Reply with a reference type. This reference is shared amongst all requests. Use onRequest hook instead. Property: %s'
|
||||
})
|
||||
|
||||
const FSTDEP007 = createDeprecation({
|
||||
code: 'FSTDEP007',
|
||||
message: 'You are trying to set a HEAD route using "exposeHeadRoute" route flag when a sibling route is already set. See documentation for more info.'
|
||||
})
|
||||
|
||||
const FSTDEP008 = createDeprecation({
|
||||
code: 'FSTDEP008',
|
||||
message: 'You are using route constraints via the route { version: "..." } option, use { constraints: { version: "..." } } option instead.'
|
||||
})
|
||||
|
||||
const FSTDEP009 = createDeprecation({
|
||||
code: 'FSTDEP009',
|
||||
message: 'You are using a custom route versioning strategy via the server { versioning: "..." } option, use { constraints: { version: "..." } } option instead.'
|
||||
})
|
||||
|
||||
const FSTDEP010 = createDeprecation({
|
||||
code: 'FSTDEP010',
|
||||
message: 'Modifying the "reply.sent" property is deprecated. Use the "reply.hijack()" method instead.'
|
||||
})
|
||||
|
||||
const FSTDEP011 = createDeprecation({
|
||||
code: 'FSTDEP011',
|
||||
message: 'Variadic listen method is deprecated. Please use ".listen(optionsObject)" instead. The variadic signature will be removed in `fastify@5`.'
|
||||
})
|
||||
|
||||
const FSTDEP012 = createDeprecation({
|
||||
code: 'FSTDEP012',
|
||||
message: 'request.context property access is deprecated. Please use "request.routeOptions.config" or "request.routeOptions.schema" instead for accessing Route settings. The "request.context" will be removed in `fastify@5`.'
|
||||
})
|
||||
|
||||
const FSTDEP013 = createDeprecation({
|
||||
code: 'FSTDEP013',
|
||||
message: 'Direct return of "trailers" function is deprecated. Please use "callback" or "async-await" for return value. The support of direct return will removed in `fastify@5`.'
|
||||
})
|
||||
|
||||
const FSTDEP014 = createDeprecation({
|
||||
code: 'FSTDEP014',
|
||||
message: 'You are trying to set/access the default route. This property is deprecated. Please, use setNotFoundHandler if you want to custom a 404 handler or the wildcard (*) to match all routes.'
|
||||
})
|
||||
|
||||
const FSTDEP015 = createDeprecation({
|
||||
code: 'FSTDEP015',
|
||||
message: 'You are accessing the deprecated "request.routeSchema" property. Use "request.routeOptions.schema" instead. Property "req.routeSchema" will be removed in `fastify@5`.'
|
||||
})
|
||||
|
||||
const FSTDEP016 = createDeprecation({
|
||||
code: 'FSTDEP016',
|
||||
message: 'You are accessing the deprecated "request.routeConfig" property. Use "request.routeOptions.config" instead. Property "req.routeConfig" will be removed in `fastify@5`.'
|
||||
})
|
||||
|
||||
const FSTDEP017 = createDeprecation({
|
||||
code: 'FSTDEP017',
|
||||
message: 'You are accessing the deprecated "request.routerPath" property. Use "request.routeOptions.url" instead. Property "req.routerPath" will be removed in `fastify@5`.'
|
||||
})
|
||||
|
||||
const FSTDEP018 = createDeprecation({
|
||||
code: 'FSTDEP018',
|
||||
message: 'You are accessing the deprecated "request.routerMethod" property. Use "request.routeOptions.method" instead. Property "req.routerMethod" will be removed in `fastify@5`.'
|
||||
})
|
||||
|
||||
const FSTDEP019 = createDeprecation({
|
||||
code: 'FSTDEP019',
|
||||
message: 'reply.context property access is deprecated. Please use "request.routeOptions.config" or "request.routeOptions.schema" instead for accessing Route settings. The "reply.context" will be removed in `fastify@5`.'
|
||||
})
|
||||
|
||||
const FSTDEP020 = createDeprecation({
|
||||
code: 'FSTDEP020',
|
||||
message: 'You are using the deprecated "reply.getResponseTime()" method. Use the "reply.elapsedTime" property instead. Method "reply.getResponseTime()" will be removed in `fastify@5`.'
|
||||
})
|
||||
|
||||
const FSTDEP021 = createDeprecation({
|
||||
code: 'FSTDEP021',
|
||||
message: 'The `reply.redirect()` method has a new signature: `reply.redirect(url: string, code?: number)`. It will be enforced in `fastify@v5`'
|
||||
})
|
||||
|
||||
const FSTDEP022 = createDeprecation({
|
||||
code: 'FSTDEP021',
|
||||
message: 'You are using the deprecated json shorthand schema on route %s. Specify full object schema instead. It will be removed in `fastify@v5`'
|
||||
})
|
||||
/**
|
||||
* Deprecation codes:
|
||||
* - FSTWRN001
|
||||
* - FSTSEC001
|
||||
* - FSTDEP022
|
||||
*
|
||||
* Deprecation Codes FSTDEP001 - FSTDEP021 were used by v4 and MUST NOT not be reused.
|
||||
* - FSTDEP022 is used by v5 and MUST NOT be reused.
|
||||
* Warning Codes FSTWRN001 - FSTWRN002 were used by v4 and MUST NOT not be reused.
|
||||
*/
|
||||
|
||||
const FSTWRN001 = createWarning({
|
||||
name: 'FastifyWarning',
|
||||
@@ -99,32 +20,38 @@ const FSTWRN001 = createWarning({
|
||||
unlimited: true
|
||||
})
|
||||
|
||||
const FSTWRN002 = createWarning({
|
||||
const FSTWRN003 = createWarning({
|
||||
name: 'FastifyWarning',
|
||||
code: 'FSTWRN002',
|
||||
message: 'The %s plugin being registered mixes async and callback styles, which will result in an error in `fastify@5`',
|
||||
code: 'FSTWRN003',
|
||||
message: 'The %s mixes async and callback styles that may lead to unhandled rejections. Please use only one of them.',
|
||||
unlimited: true
|
||||
})
|
||||
|
||||
const FSTWRN004 = createWarning({
|
||||
name: 'FastifyWarning',
|
||||
code: 'FSTWRN004',
|
||||
message: 'It seems that you are overriding an errorHandler in the same scope, which can lead to subtle bugs.',
|
||||
unlimited: true
|
||||
})
|
||||
|
||||
const FSTSEC001 = createWarning({
|
||||
name: 'FastifySecurity',
|
||||
code: 'FSTSEC001',
|
||||
message: 'You are using /%s/ Content-Type which may be vulnerable to CORS attack. Please make sure your RegExp start with "^" or include ";?" to proper detection of the essence MIME type.',
|
||||
unlimited: true
|
||||
})
|
||||
|
||||
const FSTDEP022 = createWarning({
|
||||
name: 'FastifyWarning',
|
||||
code: 'FSTDEP022',
|
||||
message: 'The router options for %s property access is deprecated. Please use "options.routerOptions" instead for accessing router options. The router options will be removed in `fastify@6`.',
|
||||
unlimited: true
|
||||
})
|
||||
|
||||
module.exports = {
|
||||
FSTDEP005,
|
||||
FSTDEP006,
|
||||
FSTDEP007,
|
||||
FSTDEP008,
|
||||
FSTDEP009,
|
||||
FSTDEP010,
|
||||
FSTDEP011,
|
||||
FSTDEP012,
|
||||
FSTDEP013,
|
||||
FSTDEP014,
|
||||
FSTDEP015,
|
||||
FSTDEP016,
|
||||
FSTDEP017,
|
||||
FSTDEP018,
|
||||
FSTDEP019,
|
||||
FSTDEP020,
|
||||
FSTDEP021,
|
||||
FSTDEP022,
|
||||
FSTWRN001,
|
||||
FSTWRN002
|
||||
FSTWRN003,
|
||||
FSTWRN004,
|
||||
FSTSEC001,
|
||||
FSTDEP022
|
||||
}
|
||||
|
||||
84
backend/node_modules/fastify/lib/wrap-thenable.js
generated
vendored
Normal file
84
backend/node_modules/fastify/lib/wrap-thenable.js
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
'use strict'
|
||||
|
||||
const {
|
||||
kReplyIsError,
|
||||
kReplyHijacked
|
||||
} = require('./symbols')
|
||||
const { setErrorStatusCode } = require('./error-status')
|
||||
|
||||
const diagnostics = require('node:diagnostics_channel')
|
||||
const channels = diagnostics.tracingChannel('fastify.request.handler')
|
||||
|
||||
function wrapThenable (thenable, reply, store) {
|
||||
if (store) store.async = true
|
||||
thenable.then(function (payload) {
|
||||
if (reply[kReplyHijacked] === true) {
|
||||
return
|
||||
}
|
||||
|
||||
if (store) {
|
||||
channels.asyncStart.publish(store)
|
||||
}
|
||||
|
||||
try {
|
||||
// this is for async functions that are using reply.send directly
|
||||
//
|
||||
// since wrap-thenable will be called when using reply.send directly
|
||||
// without actual return. the response can be sent already or
|
||||
// the request may be terminated during the reply. in this situation,
|
||||
// it require an extra checking of request.aborted to see whether
|
||||
// the request is killed by client.
|
||||
if (payload !== undefined || //
|
||||
(reply.sent === false && //
|
||||
reply.raw.headersSent === false &&
|
||||
reply.request.raw.aborted === false &&
|
||||
reply.request.socket &&
|
||||
!reply.request.socket.destroyed
|
||||
)
|
||||
) {
|
||||
// we use a try-catch internally to avoid adding a catch to another
|
||||
// promise, increase promise perf by 10%
|
||||
try {
|
||||
reply.send(payload)
|
||||
} catch (err) {
|
||||
reply[kReplyIsError] = true
|
||||
reply.send(err)
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (store) {
|
||||
channels.asyncEnd.publish(store)
|
||||
}
|
||||
}
|
||||
}, function (err) {
|
||||
if (store) {
|
||||
store.error = err
|
||||
// Set status code before publishing so subscribers see the correct value
|
||||
setErrorStatusCode(reply, err)
|
||||
channels.error.publish(store) // note that error happens before asyncStart
|
||||
channels.asyncStart.publish(store)
|
||||
}
|
||||
|
||||
try {
|
||||
if (reply.sent === true) {
|
||||
reply.log.error({ err }, 'Promise errored, but reply.sent = true was set')
|
||||
return
|
||||
}
|
||||
|
||||
reply[kReplyIsError] = true
|
||||
|
||||
reply.send(err)
|
||||
// The following should not happen
|
||||
/* c8 ignore next 3 */
|
||||
} catch (err) {
|
||||
// try-catch allow to re-throw error in error handler for async handler
|
||||
reply.send(err)
|
||||
} finally {
|
||||
if (store) {
|
||||
channels.asyncEnd.publish(store)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = wrapThenable
|
||||
50
backend/node_modules/fastify/lib/wrapThenable.js
generated
vendored
50
backend/node_modules/fastify/lib/wrapThenable.js
generated
vendored
@@ -1,50 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const {
|
||||
kReplyIsError,
|
||||
kReplyHijacked
|
||||
} = require('./symbols')
|
||||
|
||||
function wrapThenable (thenable, reply) {
|
||||
thenable.then(function (payload) {
|
||||
if (reply[kReplyHijacked] === true) {
|
||||
return
|
||||
}
|
||||
|
||||
// this is for async functions that are using reply.send directly
|
||||
//
|
||||
// since wrap-thenable will be called when using reply.send directly
|
||||
// without actual return. the response can be sent already or
|
||||
// the request may be terminated during the reply. in this situation,
|
||||
// it require an extra checking of request.aborted to see whether
|
||||
// the request is killed by client.
|
||||
if (payload !== undefined || (reply.sent === false && reply.raw.headersSent === false && reply.request.raw.aborted === false)) {
|
||||
// we use a try-catch internally to avoid adding a catch to another
|
||||
// promise, increase promise perf by 10%
|
||||
try {
|
||||
reply.send(payload)
|
||||
} catch (err) {
|
||||
reply[kReplyIsError] = true
|
||||
reply.send(err)
|
||||
}
|
||||
}
|
||||
}, function (err) {
|
||||
if (reply.sent === true) {
|
||||
reply.log.error({ err }, 'Promise errored, but reply.sent = true was set')
|
||||
return
|
||||
}
|
||||
|
||||
reply[kReplyIsError] = true
|
||||
|
||||
// try-catch allow to re-throw error in error handler for async handler
|
||||
try {
|
||||
reply.send(err)
|
||||
// The following should not happen
|
||||
/* c8 ignore next 3 */
|
||||
} catch (err) {
|
||||
reply.send(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = wrapThenable
|
||||
1
backend/node_modules/fastify/node_modules/.bin/pino
generated
vendored
Symbolic link
1
backend/node_modules/fastify/node_modules/.bin/pino
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../pino/bin.js
|
||||
23
backend/node_modules/fastify/node_modules/@fastify/error/.github/workflows/ci.yml
generated
vendored
23
backend/node_modules/fastify/node_modules/@fastify/error/.github/workflows/ci.yml
generated
vendored
@@ -1,23 +0,0 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
- next
|
||||
- 'v*'
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
uses: fastify/workflows/.github/workflows/plugins-ci.yml@v3
|
||||
with:
|
||||
license-check: true
|
||||
lint: true
|
||||
2
backend/node_modules/fastify/node_modules/@fastify/error/.taprc
generated
vendored
2
backend/node_modules/fastify/node_modules/@fastify/error/.taprc
generated
vendored
@@ -1,2 +0,0 @@
|
||||
files:
|
||||
- test/**/*.test.js
|
||||
62
backend/node_modules/fastify/node_modules/@fastify/error/README.md
generated
vendored
62
backend/node_modules/fastify/node_modules/@fastify/error/README.md
generated
vendored
@@ -1,62 +0,0 @@
|
||||
# @fastify/error
|
||||
|
||||

|
||||
[](https://www.npmjs.com/package/@fastify/error)
|
||||
[](https://standardjs.com/)
|
||||
|
||||
A small utility, used by Fastify itself, for generating consistent error objects across your codebase and plugins.
|
||||
|
||||
### Install
|
||||
```
|
||||
npm i @fastify/error
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
The module exports a function that you can use for consistent error objects, it takes 4 parameters:
|
||||
|
||||
```
|
||||
createError(code, message [, statusCode [, Base]])
|
||||
```
|
||||
|
||||
- `code` (`string`, required) - The error code, you can access it later with `error.code`. For consistency, we recommend prefixing plugin error codes with `FST_`
|
||||
- `message` (`string`, required) - The error message. You can also use interpolated strings for formatting the message.
|
||||
- `statusCode` (`number`, optional) - The status code that Fastify will use if the error is sent via HTTP.
|
||||
- `Base` (`ErrorConstructor`, optional) - The base error object that will be used. (eg `TypeError`, `RangeError`)
|
||||
|
||||
```js
|
||||
const createError = require('@fastify/error')
|
||||
const CustomError = createError('ERROR_CODE', 'Hello')
|
||||
console.log(new CustomError()) // error.message => 'Hello'
|
||||
```
|
||||
|
||||
How to use an interpolated string:
|
||||
```js
|
||||
const createError = require('@fastify/error')
|
||||
const CustomError = createError('ERROR_CODE', 'Hello %s')
|
||||
console.log(new CustomError('world')) // error.message => 'Hello world'
|
||||
```
|
||||
|
||||
How to add cause:
|
||||
```js
|
||||
const createError = require('@fastify/error')
|
||||
const CustomError = createError('ERROR_CODE', 'Hello %s')
|
||||
console.log(new CustomError('world', {cause: new Error('cause')}))
|
||||
// error.message => 'Hello world'
|
||||
// error.cause => Error('cause')
|
||||
```
|
||||
|
||||
### TypeScript
|
||||
|
||||
It is possible to limit your error constructor with a generic type using TypeScript:
|
||||
|
||||
```ts
|
||||
const CustomError = createError<[string]>('ERROR_CODE', 'Hello %s')
|
||||
new CustomError('world')
|
||||
//@ts-expect-error
|
||||
new CustomError(1)
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Licensed under [MIT](./LICENSE).
|
||||
9
backend/node_modules/fastify/node_modules/@fastify/error/benchmarks/create.js
generated
vendored
9
backend/node_modules/fastify/node_modules/@fastify/error/benchmarks/create.js
generated
vendored
@@ -1,9 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const benchmark = require('benchmark')
|
||||
const createError = require('..')
|
||||
|
||||
new benchmark.Suite()
|
||||
.add('create FastifyError', function () { createError('CODE', 'Not available') }, { minSamples: 100 })
|
||||
.on('cycle', function onCycle (event) { console.log(String(event.target)) })
|
||||
.run({ async: false })
|
||||
18
backend/node_modules/fastify/node_modules/@fastify/error/benchmarks/instantiate.js
generated
vendored
18
backend/node_modules/fastify/node_modules/@fastify/error/benchmarks/instantiate.js
generated
vendored
@@ -1,18 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const benchmark = require('benchmark')
|
||||
const createError = require('..')
|
||||
|
||||
const FastifyError = createError('CODE', 'Not available')
|
||||
const FastifyError1 = createError('CODE', 'Not %s available')
|
||||
const FastifyError2 = createError('CODE', 'Not %s available %s')
|
||||
|
||||
const cause = new Error('cause')
|
||||
new benchmark.Suite()
|
||||
.add('instantiate Error', function () { new Error() }, { minSamples: 100 }) // eslint-disable-line no-new
|
||||
.add('instantiate FastifyError', function () { new FastifyError() }, { minSamples: 100 }) // eslint-disable-line no-new
|
||||
.add('instantiate FastifyError arg 1', function () { new FastifyError1('q') }, { minSamples: 100 }) // eslint-disable-line no-new
|
||||
.add('instantiate FastifyError arg 2', function () { new FastifyError2('qq', 'ss') }, { minSamples: 100 }) // eslint-disable-line no-new
|
||||
.add('instantiate FastifyError cause', function () { new FastifyError2({ cause }) }, { minSamples: 100 }) // eslint-disable-line no-new
|
||||
.on('cycle', function onCycle (event) { console.log(String(event.target)) })
|
||||
.run({ async: false })
|
||||
13
backend/node_modules/fastify/node_modules/@fastify/error/benchmarks/no-stack.js
generated
vendored
13
backend/node_modules/fastify/node_modules/@fastify/error/benchmarks/no-stack.js
generated
vendored
@@ -1,13 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const benchmark = require('benchmark')
|
||||
const createError = require('..')
|
||||
|
||||
const FastifyError = createError('CODE', 'Not available')
|
||||
Error.stackTraceLimit = 0
|
||||
|
||||
new benchmark.Suite()
|
||||
.add('no-stack instantiate Error', function () { new Error() }, { minSamples: 100 }) // eslint-disable-line no-new
|
||||
.add('no-stack instantiate FastifyError', function () { new FastifyError() }, { minSamples: 100 }) // eslint-disable-line no-new
|
||||
.on('cycle', function onCycle (event) { console.log(String(event.target)) })
|
||||
.run({ async: false })
|
||||
11
backend/node_modules/fastify/node_modules/@fastify/error/benchmarks/toString.js
generated
vendored
11
backend/node_modules/fastify/node_modules/@fastify/error/benchmarks/toString.js
generated
vendored
@@ -1,11 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const benchmark = require('benchmark')
|
||||
const createError = require('..')
|
||||
|
||||
const FastifyError = createError('CODE', 'Not available')
|
||||
|
||||
new benchmark.Suite()
|
||||
.add('FastifyError toString', function () { new FastifyError().toString() }, { minSamples: 100 })
|
||||
.on('cycle', function onCycle (event) { console.log(String(event.target)) })
|
||||
.run({ async: false })
|
||||
53
backend/node_modules/fastify/node_modules/@fastify/error/index.js
generated
vendored
53
backend/node_modules/fastify/node_modules/@fastify/error/index.js
generated
vendored
@@ -1,53 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const { format } = require('node:util')
|
||||
|
||||
function toString () {
|
||||
return `${this.name} [${this.code}]: ${this.message}`
|
||||
}
|
||||
|
||||
function createError (code, message, statusCode = 500, Base = Error) {
|
||||
if (!code) throw new Error('Fastify error code must not be empty')
|
||||
if (!message) throw new Error('Fastify error message must not be empty')
|
||||
|
||||
code = code.toUpperCase()
|
||||
!statusCode && (statusCode = undefined)
|
||||
|
||||
function FastifyError (...args) {
|
||||
if (!new.target) {
|
||||
return new FastifyError(...args)
|
||||
}
|
||||
|
||||
this.code = code
|
||||
this.name = 'FastifyError'
|
||||
this.statusCode = statusCode
|
||||
|
||||
const lastElement = args.length - 1
|
||||
if (lastElement !== -1 && args[lastElement] && typeof args[lastElement] === 'object' && 'cause' in args[lastElement]) {
|
||||
this.cause = args.pop().cause
|
||||
}
|
||||
|
||||
this.message = format(message, ...args)
|
||||
|
||||
Error.stackTraceLimit !== 0 && Error.captureStackTrace(this, FastifyError)
|
||||
}
|
||||
|
||||
FastifyError.prototype = Object.create(Base.prototype, {
|
||||
constructor: {
|
||||
value: FastifyError,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
configurable: true
|
||||
}
|
||||
})
|
||||
|
||||
FastifyError.prototype[Symbol.toStringTag] = 'Error'
|
||||
|
||||
FastifyError.prototype.toString = toString
|
||||
|
||||
return FastifyError
|
||||
}
|
||||
|
||||
module.exports = createError
|
||||
module.exports.default = createError
|
||||
module.exports.createError = createError
|
||||
45
backend/node_modules/fastify/node_modules/@fastify/error/package.json
generated
vendored
45
backend/node_modules/fastify/node_modules/@fastify/error/package.json
generated
vendored
@@ -1,45 +0,0 @@
|
||||
{
|
||||
"name": "@fastify/error",
|
||||
"version": "3.4.1",
|
||||
"description": "A small utility, used by Fastify itself, for generating consistent error objects across your codebase and plugins.",
|
||||
"main": "index.js",
|
||||
"type": "commonjs",
|
||||
"types": "types/index.d.ts",
|
||||
"scripts": {
|
||||
"lint": "standard",
|
||||
"lint:fix": "standard --fix",
|
||||
"test": "npm run test:unit && npm run test:typescript",
|
||||
"test:unit": "tap",
|
||||
"test:typescript": "tsd"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/fastify/fastify-error.git"
|
||||
},
|
||||
"keywords": [
|
||||
"fastify",
|
||||
"error",
|
||||
"utility",
|
||||
"plugin"
|
||||
],
|
||||
"author": "Tomas Della Vedova",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/fastify/fastify-error/issues"
|
||||
},
|
||||
"homepage": "https://github.com/fastify/fastify-error#readme",
|
||||
"devDependencies": {
|
||||
"benchmark": "^2.1.4",
|
||||
"standard": "^17.0.0",
|
||||
"tap": "^16.0.0",
|
||||
"tsd": "^0.29.0"
|
||||
},
|
||||
"tsd": {
|
||||
"compilerOptions": {
|
||||
"esModuleInterop": true
|
||||
}
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
184
backend/node_modules/fastify/node_modules/@fastify/error/test/index.test.js
generated
vendored
184
backend/node_modules/fastify/node_modules/@fastify/error/test/index.test.js
generated
vendored
@@ -1,184 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('tap')
|
||||
const createError = require('..')
|
||||
|
||||
test('Create error with zero parameter', t => {
|
||||
t.plan(6)
|
||||
|
||||
const NewError = createError('CODE', 'Not available')
|
||||
const err = new NewError()
|
||||
t.ok(err instanceof Error)
|
||||
t.equal(err.name, 'FastifyError')
|
||||
t.equal(err.message, 'Not available')
|
||||
t.equal(err.code, 'CODE')
|
||||
t.equal(err.statusCode, 500)
|
||||
t.ok(err.stack)
|
||||
})
|
||||
|
||||
test('Create error with 1 parameter', t => {
|
||||
t.plan(6)
|
||||
|
||||
const NewError = createError('CODE', 'hey %s')
|
||||
const err = new NewError('alice')
|
||||
t.ok(err instanceof Error)
|
||||
t.equal(err.name, 'FastifyError')
|
||||
t.equal(err.message, 'hey alice')
|
||||
t.equal(err.code, 'CODE')
|
||||
t.equal(err.statusCode, 500)
|
||||
t.ok(err.stack)
|
||||
})
|
||||
|
||||
test('Create error with 1 parameter set to undefined', t => {
|
||||
t.plan(1)
|
||||
|
||||
const NewError = createError('CODE', 'hey %s')
|
||||
const err = new NewError(undefined)
|
||||
t.equal(err.message, 'hey undefined')
|
||||
})
|
||||
|
||||
test('Create error with 2 parameters', (t) => {
|
||||
t.plan(6)
|
||||
|
||||
const NewError = createError('CODE', 'hey %s, I like your %s')
|
||||
const err = new NewError('alice', 'attitude')
|
||||
t.ok(err instanceof Error)
|
||||
t.equal(err.name, 'FastifyError')
|
||||
t.equal(err.message, 'hey alice, I like your attitude')
|
||||
t.equal(err.code, 'CODE')
|
||||
t.equal(err.statusCode, 500)
|
||||
t.ok(err.stack)
|
||||
})
|
||||
|
||||
test('Create error with 2 parameters set to undefined', t => {
|
||||
t.plan(1)
|
||||
|
||||
const NewError = createError('CODE', 'hey %s, I like your %s')
|
||||
const err = new NewError(undefined, undefined)
|
||||
t.equal(err.message, 'hey undefined, I like your undefined')
|
||||
})
|
||||
|
||||
test('Create error with 3 parameters', t => {
|
||||
t.plan(6)
|
||||
|
||||
const NewError = createError('CODE', 'hey %s, I like your %s %s')
|
||||
const err = new NewError('alice', 'attitude', 'see you')
|
||||
t.ok(err instanceof Error)
|
||||
t.equal(err.name, 'FastifyError')
|
||||
t.equal(err.message, 'hey alice, I like your attitude see you')
|
||||
t.equal(err.code, 'CODE')
|
||||
t.equal(err.statusCode, 500)
|
||||
t.ok(err.stack)
|
||||
})
|
||||
|
||||
test('Create error with 3 parameters set to undefined', t => {
|
||||
t.plan(4)
|
||||
|
||||
const NewError = createError('CODE', 'hey %s, I like your %s %s')
|
||||
const err = new NewError(undefined, undefined, undefined)
|
||||
t.equal(err.message, 'hey undefined, I like your undefined undefined')
|
||||
t.equal(err.code, 'CODE')
|
||||
t.equal(err.statusCode, 500)
|
||||
t.ok(err.stack)
|
||||
})
|
||||
|
||||
test('Create error with 4 parameters set to undefined', t => {
|
||||
t.plan(4)
|
||||
|
||||
const NewError = createError('CODE', 'hey %s, I like your %s %s and %s')
|
||||
const err = new NewError(undefined, undefined, undefined, undefined)
|
||||
t.equal(err.message, 'hey undefined, I like your undefined undefined and undefined')
|
||||
t.equal(err.code, 'CODE')
|
||||
t.equal(err.statusCode, 500)
|
||||
t.ok(err.stack)
|
||||
})
|
||||
|
||||
test('Create error with no statusCode property', t => {
|
||||
t.plan(6)
|
||||
|
||||
const NewError = createError('CODE', 'hey %s', 0)
|
||||
const err = new NewError('dude')
|
||||
t.ok(err instanceof Error)
|
||||
t.equal(err.name, 'FastifyError')
|
||||
t.equal(err.message, 'hey dude')
|
||||
t.equal(err.code, 'CODE')
|
||||
t.equal(err.statusCode, undefined)
|
||||
t.ok(err.stack)
|
||||
})
|
||||
|
||||
test('Should throw when error code has no fastify code', t => {
|
||||
t.plan(1)
|
||||
|
||||
t.throws(() => createError(), new Error('Fastify error code must not be empty'))
|
||||
})
|
||||
|
||||
test('Should throw when error code has no message', t => {
|
||||
t.plan(1)
|
||||
|
||||
t.throws(() => createError('code'), new Error('Fastify error message must not be empty'))
|
||||
})
|
||||
|
||||
test('Create error with different base', t => {
|
||||
t.plan(7)
|
||||
|
||||
const NewError = createError('CODE', 'hey %s', 500, TypeError)
|
||||
const err = new NewError('dude')
|
||||
t.ok(err instanceof Error)
|
||||
t.ok(err instanceof TypeError)
|
||||
t.equal(err.name, 'FastifyError')
|
||||
t.equal(err.message, 'hey dude')
|
||||
t.equal(err.code, 'CODE')
|
||||
t.equal(err.statusCode, 500)
|
||||
t.ok(err.stack)
|
||||
})
|
||||
|
||||
test('FastifyError.toString returns code', t => {
|
||||
t.plan(1)
|
||||
|
||||
const NewError = createError('CODE', 'foo')
|
||||
const err = new NewError()
|
||||
t.equal(err.toString(), 'FastifyError [CODE]: foo')
|
||||
})
|
||||
|
||||
test('Create the error without the new keyword', t => {
|
||||
t.plan(6)
|
||||
|
||||
const NewError = createError('CODE', 'Not available')
|
||||
const err = NewError()
|
||||
t.ok(err instanceof Error)
|
||||
t.equal(err.name, 'FastifyError')
|
||||
t.equal(err.message, 'Not available')
|
||||
t.equal(err.code, 'CODE')
|
||||
t.equal(err.statusCode, 500)
|
||||
t.ok(err.stack)
|
||||
})
|
||||
|
||||
test('Create an error with cause', t => {
|
||||
t.plan(2)
|
||||
const cause = new Error('HEY')
|
||||
const NewError = createError('CODE', 'Not available')
|
||||
const err = NewError({ cause })
|
||||
|
||||
t.ok(err instanceof Error)
|
||||
t.equal(err.cause, cause)
|
||||
})
|
||||
|
||||
test('Create an error with cause and message', t => {
|
||||
t.plan(2)
|
||||
const cause = new Error('HEY')
|
||||
const NewError = createError('CODE', 'Not available: %s')
|
||||
const err = NewError('foo', { cause })
|
||||
|
||||
t.ok(err instanceof Error)
|
||||
t.equal(err.cause, cause)
|
||||
})
|
||||
|
||||
test('Create an error with last argument null', t => {
|
||||
t.plan(2)
|
||||
const cause = new Error('HEY')
|
||||
const NewError = createError('CODE', 'Not available')
|
||||
const err = NewError({ cause }, null)
|
||||
|
||||
t.ok(err instanceof Error)
|
||||
t.notOk(err.cause)
|
||||
})
|
||||
44
backend/node_modules/fastify/node_modules/@fastify/error/types/index.d.ts
generated
vendored
44
backend/node_modules/fastify/node_modules/@fastify/error/types/index.d.ts
generated
vendored
@@ -1,44 +0,0 @@
|
||||
declare function createError<C extends string, SC extends number, Arg extends unknown[] = [any?, any?, any?]> (
|
||||
code: C,
|
||||
message: string,
|
||||
statusCode: SC,
|
||||
Base?: ErrorConstructor
|
||||
): createError.FastifyErrorConstructor<{ code: C, statusCode: SC }, Arg>
|
||||
|
||||
declare function createError<C extends string, Arg extends unknown[] = [any?, any?, any?]> (
|
||||
code: C,
|
||||
message: string,
|
||||
statusCode?: number,
|
||||
Base?: ErrorConstructor
|
||||
): createError.FastifyErrorConstructor<{ code: C }, Arg>
|
||||
|
||||
declare function createError<Arg extends unknown[] = [any?, any?, any?]> (
|
||||
code: string,
|
||||
message: string,
|
||||
statusCode?: number,
|
||||
Base?: ErrorConstructor
|
||||
): createError.FastifyErrorConstructor<{ code: string }, Arg>
|
||||
|
||||
type CreateError = typeof createError
|
||||
|
||||
declare namespace createError {
|
||||
export interface FastifyError extends Error {
|
||||
code: string
|
||||
name: string
|
||||
statusCode?: number
|
||||
}
|
||||
|
||||
export interface FastifyErrorConstructor<
|
||||
E extends { code: string, statusCode?: number } = { code: string, statusCode?: number },
|
||||
T extends unknown[] = [any?, any?, any?]
|
||||
> {
|
||||
new(...arg: T): FastifyError & E
|
||||
(...arg: T): FastifyError & E
|
||||
readonly prototype: FastifyError & E
|
||||
}
|
||||
|
||||
export const createError: CreateError
|
||||
export { createError as default }
|
||||
}
|
||||
|
||||
export = createError
|
||||
72
backend/node_modules/fastify/node_modules/@fastify/error/types/index.test-d.ts
generated
vendored
72
backend/node_modules/fastify/node_modules/@fastify/error/types/index.test-d.ts
generated
vendored
@@ -1,72 +0,0 @@
|
||||
import createError, { FastifyError, FastifyErrorConstructor } from '..'
|
||||
import { expectType, expectError } from 'tsd'
|
||||
|
||||
const CustomError = createError('ERROR_CODE', 'message')
|
||||
expectType<FastifyErrorConstructor<{ code: 'ERROR_CODE' }>>(CustomError)
|
||||
const err = new CustomError()
|
||||
expectType<FastifyError & { code: 'ERROR_CODE' }>(err)
|
||||
expectType<'ERROR_CODE'>(err.code)
|
||||
expectType<string>(err.message)
|
||||
expectType<number | undefined>(err.statusCode)
|
||||
|
||||
const CustomTypedError = createError('OTHER_CODE', 'message', 400)
|
||||
expectType<FastifyErrorConstructor<{ code: 'OTHER_CODE', statusCode: 400 }>>(CustomTypedError)
|
||||
const typed = new CustomTypedError()
|
||||
expectType<FastifyError & { code: 'OTHER_CODE', statusCode: 400 }>(typed)
|
||||
expectType<'OTHER_CODE'>(typed.code)
|
||||
expectType<string>(typed.message)
|
||||
expectType<400>(typed.statusCode)
|
||||
|
||||
/* eslint-disable no-new */
|
||||
const CustomTypedArgError = createError<[string]>('OTHER_CODE', 'expect %s message', 400)
|
||||
CustomTypedArgError('a')
|
||||
expectError(CustomTypedArgError('a', 'b'))
|
||||
expectError(new CustomTypedArgError('a', 'b'))
|
||||
expectError(CustomTypedArgError(1))
|
||||
expectError(new CustomTypedArgError(1))
|
||||
|
||||
const CustomTypedArgError2 = createError<string, number, [string]>('OTHER_CODE', 'expect %s message', 400)
|
||||
CustomTypedArgError2('a')
|
||||
expectError(CustomTypedArgError2('a', 'b'))
|
||||
expectError(new CustomTypedArgError2('a', 'b'))
|
||||
expectError(CustomTypedArgError2(1))
|
||||
expectError(new CustomTypedArgError2(1))
|
||||
|
||||
const CustomTypedArgError3 = createError<string, number, [string, string]>('OTHER_CODE', 'expect %s message but got %s', 400)
|
||||
expectError(CustomTypedArgError3('a'))
|
||||
CustomTypedArgError3('a', 'b')
|
||||
new CustomTypedArgError3('a', 'b')
|
||||
expectError(CustomTypedArgError3(1))
|
||||
expectError(new CustomTypedArgError3(1))
|
||||
expectError(new CustomTypedArgError3(1, 2))
|
||||
expectError(new CustomTypedArgError3('1', 2))
|
||||
expectError(new CustomTypedArgError3(1, '2'))
|
||||
|
||||
const CustomTypedArgError4 = createError<string, number, [string, string]>('OTHER_CODE', 'expect %s message but got %s', 400)
|
||||
expectError(CustomTypedArgError4('a'))
|
||||
CustomTypedArgError4('a', 'b')
|
||||
new CustomTypedArgError4('a', 'b')
|
||||
expectError(CustomTypedArgError4(1))
|
||||
expectError(new CustomTypedArgError4(1))
|
||||
expectError(new CustomTypedArgError4(1, 2))
|
||||
expectError(new CustomTypedArgError4('1', 2))
|
||||
expectError(new CustomTypedArgError4(1, '2'))
|
||||
|
||||
const CustomTypedArgError5 = createError<[string, string, string, string]>('OTHER_CODE', 'expect %s message but got %s. Please contact %s by emailing to %s', 400)
|
||||
expectError(CustomTypedArgError5('a'))
|
||||
expectError(new CustomTypedArgError5('a', 'b'))
|
||||
expectError(new CustomTypedArgError5('a', 'b', 'c'))
|
||||
CustomTypedArgError5('a', 'b', 'c', 'd')
|
||||
expectError(new CustomTypedArgError5('a', 'b', 'c', 'd', 'e'))
|
||||
|
||||
const CustomTypedArgError6 = createError<string, number, [string, string, string, string]>('OTHER_CODE', 'expect %s message but got %s. Please contact %s by emailing to %s', 400)
|
||||
expectError(CustomTypedArgError6('a'))
|
||||
expectError(new CustomTypedArgError6('a', 'b'))
|
||||
expectError(new CustomTypedArgError6('a', 'b', 'c'))
|
||||
CustomTypedArgError6('a', 'b', 'c', 'd')
|
||||
expectError(new CustomTypedArgError6('a', 'b', 'c', 'd', 'e'))
|
||||
|
||||
|
||||
const CustomErrorWithErrorConstructor = createError('ERROR_CODE', 'message', 500, TypeError)
|
||||
expectType<FastifyErrorConstructor<{ code: 'ERROR_CODE', statusCode: 500 }>>(CustomErrorWithErrorConstructor)
|
||||
CustomErrorWithErrorConstructor({cause: new Error('Error')})
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user