Socket
Socket
Sign inDemoInstall

fastify

Package Overview
Dependencies
Maintainers
0
Versions
288
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fastify - npm Package Compare versions

Comparing version 4.28.0 to 5.0.0-alpha.2

.tap/processinfo/09002e93-10ad-430c-bc86-c0576928b0ed.json

5

build/build-error-serializer.js

@@ -21,6 +21,8 @@ /* istanbul ignore file */

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) {

@@ -34,1 +36,2 @@ fs.writeFileSync(file, moduleCode)

}
/* c8 ignore stop */

9

build/build-validation.js

@@ -12,6 +12,7 @@ 'use strict'

const moduleCode = `// This file is autogenerated by ${__filename.replace(__dirname, 'build')}, do not edit
/* istanbul ignore file */
/* c8 ignore start */
${schemaValidationCode}
module.exports.defaultInitOptions = ${JSON.stringify(defaultInitOptions)}
/* c8 ignore stop */
`

@@ -42,7 +43,7 @@

pluginTimeout: 10000,
requestIdHeader: 'request-id',
requestIdHeader: false,
requestIdLogLabel: 'reqId',
http2SessionTimeout: 72000, // 72 seconds
exposeHeadRoutes: true,
useSemicolonDelimiter: true
useSemicolonDelimiter: false
}

@@ -103,3 +104,3 @@

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 },

@@ -106,0 +107,0 @@ http2SessionTimeout: { type: 'integer', default: defaultInitOptions.http2SessionTimeout },

@@ -248,3 +248,3 @@ <h1 align="center">Fastify</h1>

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 need to follow the
pattern: ` [version].[action].[optional-description].sql`.

@@ -251,0 +251,0 @@

@@ -106,3 +106,3 @@ <h1 align="center">Fastify</h1>

server.decorate('magicKey', null)
server.decorate('magicKey')

@@ -307,3 +307,3 @@ server.listen({ port: '1234' }, () => {

// Set up the placeholder for the magicKey
fastify.decorate('magicKey', null)
fastify.decorate('magicKey')

@@ -411,3 +411,3 @@ // Our magic -- important to make sure errors are handled. Beware of async

```js
fastify.decorate('magicKey', null)
fastify.decorate('magicKey')
```

@@ -414,0 +414,0 @@

@@ -450,2 +450,4 @@ <h1 align="center">Fastify</h1>

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)

@@ -452,0 +454,0 @@ Fastify plugin to parse request language.

@@ -22,3 +22,4 @@ <h1 align="center">Fastify</h1>

// 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;
}

@@ -31,4 +32,5 @@ ```

// 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;
}
```

@@ -32,2 +32,9 @@ <h1 align="center">Fastify</h1>

> ## ⚠ Security Notice
> When using with RegExp to detect `Content-Type`, you should beware of
> how to properly detect the `Content-Type`. For example, if you need
> `application/*`, you should use `/^application\/([\w-]+);?/` to match the
> [essence MIME type](https://mimesniff.spec.whatwg.org/#mime-type-miscellaneous)
> only.
### Usage

@@ -56,3 +63,3 @@ ```js

// 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) {

@@ -85,2 +92,24 @@ done(err, body)

### Using addContentTypeParser with fastify.register
When using `addContentTypeParser` in combination with `fastify.register`,
`await` should not be used when registering routes. Using `await` causes
the route registration to be asynchronous and can lead to routes being registered
before the addContentTypeParser has been 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) => {});
});
```
Besides the `addContentTypeParser` API there are further APIs that can be used.

@@ -87,0 +116,0 @@ These are `hasContentTypeParser`, `removeContentTypeParser` and

@@ -62,4 +62,4 @@ <h1 align="center">Fastify</h1>

Remember this example works only with value types as reference types will be
shared amongst all requests. See [decorateRequest](#decorate-request).
Remember this example works only with value types as reference types will
thrown and error during the fastify startup. See [decorateRequest](#decorate-request).

@@ -87,3 +87,3 @@ See [JavaScript engine fundamentals: Shapes and Inline

As mentioned above, non-function values can be attached:
As mentioned above, non-function values can be attached to the server instance as:

@@ -182,3 +182,3 @@ ```js

Note: using `decorateReply` will emit a warning if used with a reference type:
Note: using `decorateReply` will throw and error if used with a reference type:

@@ -189,8 +189,9 @@ ```js

```
In this example, the reference of the object is shared with all the requests:
**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:
In this example, the reference of the object would be shared with all the requests
and **any mutation will impact all requests, potentially creating security
vulnerabilities or memory leaks**, so Fastify blocks it.
To achieve proper encapsulation across requests configure a new value for each
incoming request in the [`'onRequest'` hook](./Hooks.md#onrequest). Example:
```js

@@ -200,3 +201,3 @@ const fp = require('fastify-plugin')

async function myPlugin (app) {
app.decorateRequest('foo', null)
app.decorateRequest('foo')
app.addHook('onRequest', async (req, reply) => {

@@ -227,3 +228,3 @@ req.foo = { bar: 42 }

Note: using `decorateRequest` will emit a warning if used with a reference type:
Note: using `decorateRequest` will emit an error if used with a reference type:

@@ -234,9 +235,11 @@ ```js

```
In this example, the reference of the object is shared with all the requests:
**any mutation will impact all requests, potentially creating security
vulnerabilities or memory leaks**.
In this example, the reference of the object would be shared with all the requests
and **any mutation will impact all requests, potentially creating security
vulnerabilities or memory leaks**, so Fastify blocks it.
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

@@ -246,3 +249,3 @@ const fp = require('fastify-plugin')

async function myPlugin (app) {
app.decorateRequest('foo', null)
app.decorateRequest('foo')
app.addHook('onRequest', async (req, reply) => {

@@ -256,2 +259,25 @@ req.foo = { bar: 42 }

The hook solution is more flexible and allows for more complex initialization
because you can add more logic 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.

@@ -258,0 +284,0 @@

@@ -39,2 +39,3 @@ <h1 align="center">Fastify</h1>

- [FST_ERR_DEC_AFTER_START](#fst_err_dec_after_start)
- [FST_ERR_DEC_REFERENCE_TYPE](#fst_err_dec_reference_type)
- [FST_ERR_HOOK_INVALID_TYPE](#fst_err_hook_invalid_type)

@@ -48,2 +49,5 @@ - [FST_ERR_HOOK_INVALID_HANDLER](#fst_err_hook_invalid_handler)

- [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)

@@ -75,3 +79,2 @@ - [FST_ERR_REP_RESPONSE_BODY_CONSUMED](#fst_err_rep_response_body_consumed)

- [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)

@@ -96,2 +99,3 @@ - [FST_ERR_ROUTE_OPTIONS_NOT_OBJ](#fst_err_route_options_not_obj)

- [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)

@@ -312,2 +316,3 @@ - [FST_ERR_LISTEN_OPTIONS_INVALID](#fst_err_listen_options_invalid)

| <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_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) |

@@ -321,2 +326,5 @@ | <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_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) |

@@ -348,3 +356,2 @@ | <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_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) |

@@ -369,2 +376,3 @@ | <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_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) |

@@ -371,0 +379,0 @@ | <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) |

@@ -832,14 +832,13 @@ <h1 align="center">Fastify</h1>

> **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.
> its API is subject to change even in semver-patch releases of Node.js. As some
> versions of Node.js are supported by Fastify where `diagnostics_channel` is
> unavailable, or with an incomplete feature set, the hook uses the
> [dc-polyfill](https://www.npmjs.com/package/dc-polyfill) package to provide a
> polyfill.
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.

@@ -853,3 +852,3 @@ For example, a tracing package might do something like the following (which is,

const tracer = /* retrieved from elsewhere in the package */
const dc = require('node:diagnostics_channel')
const dc = require('node:diagnostics_channel') // or require('dc-polyfill')
const channel = dc.channel('fastify.initialization')

@@ -860,3 +859,3 @@ const spans = new WeakMap()

fastify.addHook('onRequest', (request, reply, done) => {
const span = tracer.startSpan('fastify.request')
const span = tracer.startSpan('fastify.request.handler')
spans.set(request, span)

@@ -873,1 +872,36 @@ done()

```
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') // or require('dc-polyfill')
const channel = dc.channel('tracing:fastify.request.handler:start')
channel.subscribe((msg) => {
console.log(msg.request, msg.reply)
})
```

@@ -101,6 +101,6 @@ <h1 align="center">Fastify</h1>

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`](./Server.md#factory-request-id-header) and Fastify Factory
[`genReqId`](./Server.md#genreqid) for customization options.
requestIdHeader-option is set and the corresponding header is present than
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.

@@ -247,3 +247,3 @@ The default logger is configured with a set of standard serializers that

headers: request.headers,
hostname: request.hostname,
host: request.host,
remoteAddress: request.ip,

@@ -250,0 +250,0 @@ remotePort: request.socket.remotePort

@@ -61,2 +61,4 @@ <h1 align="center">Fastify</h1>

- `.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.

@@ -94,4 +96,2 @@ - `.hasTrailer(key)` - Determine if a trailer has been set.

- `.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.

@@ -248,2 +248,23 @@

### .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)

@@ -349,18 +370,2 @@ <a id="trailer"></a>

### .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)

@@ -367,0 +372,0 @@ <a id="type"></a>

@@ -23,6 +23,8 @@ <h1 align="center">Fastify</h1>

[`trustProxy`](./Server.md#factory-trust-proxy) option is enabled)
- `hostname` - the host of the incoming request (derived from `X-Forwarded-Host`
- `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.
- `hostname` - the host of the incoming request without the port
- `port` - the port that the server is listening on
- `protocol` - the protocol of the incoming request (`https` or `http`)

@@ -108,3 +110,5 @@ - `method` - the method of the incoming request

console.log(request.ips)
console.log(request.host)
console.log(request.hostname)
console.log(request.port)
console.log(request.protocol)

@@ -111,0 +115,0 @@ console.log(request.url)

@@ -193,2 +193,20 @@ <h1 align="center">Fastify</h1>

`fastify.propfind(path, [options], handler)`
`fastify.proppatch(path, [options], handler)`
`fastify.mkcol(path, [options], handler)`
`fastify.copy(path, [options], handler)`
`fastify.move(path, [options], handler)`
`fastify.lock(path, [options], handler)`
`fastify.unlock(path, [options], handler)`
`fastify.trace(path, [options], handler)`
`fastify.search(path, [options], handler)`
Example:

@@ -472,3 +490,3 @@ ```js

fastify.register(function(app, _, done) {
fastify.register(function (app, _, done) {
app.get('/users', () => {})

@@ -480,3 +498,3 @@ app.route(route)

await fastify.listen({ port: 0 })
await fastify.listen({ port: 3000 })
```

@@ -584,3 +602,3 @@

headers: req.headers,
hostname: req.hostname,
host: req.host,
remoteAddress: req.ip,

@@ -757,3 +775,3 @@ remotePort: req.socket.remotePort

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) {

@@ -807,4 +825,4 @@ reply.send('hello world from ' + request.headers.host)

> const fastify = Fastify({
> frameworkErrors: function(err, res, res) {
> if(err instanceof Fastify.errorCodes.FST_ERR_ASYNC_CONSTRAINT) {
> frameworkErrors: function (err, res, res) {
> if (err instanceof Fastify.errorCodes.FST_ERR_ASYNC_CONSTRAINT) {
> res.code(400)

@@ -818,23 +836,1 @@ > return res.send("Invalid header provided")

> ```
### ⚠ 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).

@@ -40,25 +40,22 @@ <h1 align="center">Fastify</h1>

```typescript
import fastify from 'fastify'
import { JsonSchemaToTsProvider } from '@fastify/type-provider-json-schema-to-ts'
import fastify from 'fastify'
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!
})

@@ -76,21 +73,19 @@ ```

```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!
})

@@ -97,0 +92,0 @@ ```

@@ -664,2 +664,19 @@ <h1 align="center">Fastify</h1>

are actually being loaded.
- In case you've the `@typescript-eslint/no-floating-promises` enabled,
please double-check that your ESLint configuration includes a `allowForKnownSafePromises`
property as described on the [`typescript-eslint no-floating-promises allowForKnownSafePromises
documentation`](https://typescript-eslint.io/rules/no-floating-promises/#allowforknownsafepromises):
```
{
"rules": {
"@typescript-eslint/no-floating-promises": ["error", {
"allowForKnownSafePromises": [
{ "from": "package", "name": "FastifyInstance", "package": "fastify" },
{ "from": "package", "name": "FastifyReply", "package": "fastify" },
{ "from": "package", "name": "SafePromiseLike", "package": "fastify" },
]
}]
}
}
```
- Use a module such as [depcheck](https://www.npmjs.com/package/depcheck) or

@@ -835,3 +852,3 @@ [npm-check](https://www.npmjs.com/package/npm-check) to verify plugin

##### 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)

@@ -991,3 +1008,3 @@

##### fastify.FastifyServerOptions<[RawServer][RawServerGeneric], [Logger][LoggerGeneric]>
##### fastify.FastifyServerOptions< [RawServer][RawServerGeneric], [Logger][LoggerGeneric]>

@@ -1003,3 +1020,3 @@ [src](https://github.com/fastify/fastify/blob/main/fastify.d.ts#L29)

##### fastify.FastifyInstance<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RequestGeneric][FastifyRequestGenericInterface], [Logger][LoggerGeneric]>
##### fastify.FastifyInstance< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RequestGeneric][FastifyRequestGenericInterface], [Logger][LoggerGeneric]>

@@ -1027,3 +1044,3 @@ [src](https://github.com/fastify/fastify/blob/main/types/instance.d.ts#L16)

##### 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)

@@ -1128,3 +1145,3 @@

##### fastify.FastifyReply<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>
##### fastify.FastifyReply< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>
[src](https://github.com/fastify/fastify/blob/main/types/reply.d.ts#L32)

@@ -1165,3 +1182,3 @@

##### fastify.RawReplyDefaultExpression<[RawServer][RawServerGeneric]>
##### fastify.RawReplyDefaultExpression< [RawServer][RawServerGeneric]>
[src](https://github.com/fastify/fastify/blob/main/types/utils.d.ts#L27)

@@ -1198,3 +1215,3 @@

##### fastify.FastifyPluginCallback<[Options][FastifyPluginOptions]>
##### fastify.FastifyPluginCallback< [Options][FastifyPluginOptions]>
[src](https://github.com/fastify/fastify/blob/main/types/plugin.d.ts#L9)

@@ -1205,3 +1222,3 @@

##### fastify.FastifyPluginAsync<[Options][FastifyPluginOptions]>
##### fastify.FastifyPluginAsync< [Options][FastifyPluginOptions]>
[src](https://github.com/fastify/fastify/blob/main/types/plugin.d.ts#L20)

@@ -1212,3 +1229,3 @@

##### fastify.FastifyPlugin<[Options][FastifyPluginOptions]>
##### fastify.FastifyPlugin< [Options][FastifyPluginOptions]>
[src](https://github.com/fastify/fastify/blob/main/types/plugin.d.ts#L29)

@@ -1282,3 +1299,3 @@

##### fastify.FastifyLoggerOptions<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric]>
##### fastify.FastifyLoggerOptions< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric]>

@@ -1346,3 +1363,3 @@ [src](https://github.com/fastify/fastify/blob/main/types/logger.d.ts#L17)

##### fastify.RouteHandlerMethod<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>
##### fastify.RouteHandlerMethod< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>

@@ -1357,3 +1374,3 @@ [src](https://github.com/fastify/fastify/blob/main/types/route.d.ts#L105)

##### fastify.RouteOptions<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>
##### fastify.RouteOptions< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>

@@ -1370,3 +1387,3 @@ [src](https://github.com/fastify/fastify/blob/main/types/route.d.ts#L78)

##### fastify.RouteShorthandMethod<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric]>
##### fastify.RouteShorthandMethod< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric]>

@@ -1378,3 +1395,3 @@ [src](https://github.com/fastify/fastify/blob/main/types/route.d.ts#12)

##### fastify.RouteShorthandOptions<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>
##### fastify.RouteShorthandOptions< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>

@@ -1387,3 +1404,3 @@ [src](https://github.com/fastify/fastify/blob/main/types/route.d.ts#55)

##### fastify.RouteShorthandOptionsWithHandler<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>
##### fastify.RouteShorthandOptionsWithHandler< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric], [RawReply][RawReplyGeneric], [RequestGeneric][FastifyRequestGenericInterface], [ContextConfig][ContextConfigGeneric]>

@@ -1403,3 +1420,3 @@ [src](https://github.com/fastify/fastify/blob/main/types/route.d.ts#93)

##### fastify.FastifyBodyParser<[RawBody][RawBodyGeneric], [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric]>
##### fastify.FastifyBodyParser< [RawBody][RawBodyGeneric], [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric]>

@@ -1411,3 +1428,3 @@ [src](https://github.com/fastify/fastify/blob/main/types/content-type-parser.d.ts#L7)

##### fastify.FastifyContentTypeParser<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric]>
##### fastify.FastifyContentTypeParser< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric]>

@@ -1419,3 +1436,3 @@ [src](https://github.com/fastify/fastify/blob/main/types/content-type-parser.d.ts#L17)

##### fastify.AddContentTypeParser<[RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric]>
##### fastify.AddContentTypeParser< [RawServer][RawServerGeneric], [RawRequest][RawRequestGeneric]>

@@ -1462,3 +1479,3 @@ [src](https://github.com/fastify/fastify/blob/main/types/content-type-parser.d.ts#L46)

##### 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

@@ -1473,3 +1490,3 @@ [src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L17)

##### 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

@@ -1489,3 +1506,3 @@ [src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L35)

##### 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

@@ -1497,3 +1514,3 @@ [src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L53)

##### 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

@@ -1505,3 +1522,3 @@ [src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L70)

##### 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

@@ -1516,3 +1533,3 @@ [src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L94)

##### 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

@@ -1528,3 +1545,3 @@ [src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L114)

##### 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

@@ -1540,3 +1557,3 @@ [src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L134)

##### 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

@@ -1558,3 +1575,3 @@ [src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L154)

##### 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

@@ -1567,3 +1584,3 @@ [src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L174)

##### 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

@@ -1580,3 +1597,3 @@ [src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L191)

##### 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

@@ -1583,0 +1600,0 @@ [src](https://github.com/fastify/fastify/blob/main/types/hooks.d.ts#L206)

@@ -12,3 +12,2 @@

- [FSTDEP005](#FSTDEP005)
- [FSTDEP006](#FSTDEP006)
- [FSTDEP007](#FSTDEP007)

@@ -18,6 +17,4 @@ - [FSTDEP008](#FSTDEP008)

- [FSTDEP010](#FSTDEP010)
- [FSTDEP011](#FSTDEP011)
- [FSTDEP012](#FSTDEP012)
- [FSTDEP013](#FSTDEP013)
- [FSTDEP014](#FSTDEP014)
- [FSTDEP015](#FSTDEP015)

@@ -28,3 +25,2 @@ - [FSTDEP016](#FSTDEP016)

- [FSTDEP019](#FSTDEP019)
- [FSTDEP020](#FSTDEP020)
- [FSTDEP021](#FSTDEP021)

@@ -82,3 +78,2 @@

| <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) |

@@ -88,6 +83,4 @@ | <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="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) |

@@ -98,3 +91,2 @@ | <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="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) |

@@ -13,4 +13,4 @@ /**

import fastify, { FastifyInstance, RouteShorthandOptions } from '../fastify';
import { Server, IncomingMessage, ServerResponse } from 'http';
import fastify, { FastifyInstance, RouteShorthandOptions } from '../fastify'
import { Server, IncomingMessage, ServerResponse } from 'http'

@@ -24,3 +24,3 @@ // Create an http server. We pass the relevant typings for our http version used.

ServerResponse
> = fastify({ logger: true });
> = fastify({ logger: true })

@@ -58,3 +58,3 @@ // Define interfaces for our request. We can create these automatically

}
};
}

@@ -68,8 +68,8 @@ // Add our route handler with correct types

}>('/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!' })
})

@@ -79,6 +79,6 @@ // Start your server

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}`)
})

@@ -25,3 +25,3 @@ import * as http from 'http'

import { FastifyServerFactory, FastifyServerFactoryHandler } from './types/serverFactory'
import { FastifyTypeProvider, FastifyTypeProviderDefault } from './types/type-provider'
import { FastifyTypeProvider, FastifyTypeProviderDefault, SafePromiseLike } from './types/type-provider'
import { HTTPMethods, RawServerBase, RawRequestDefaultExpression, RawReplyDefaultExpression, RawServerDefault, ContextConfigDefault, RequestBodyDefault, RequestQuerystringDefault, RequestParamsDefault, RequestHeadersDefault } from './types/utils'

@@ -39,3 +39,3 @@

declare namespace fastify {
export const errorCodes: FastifyErrorCodes;
export const errorCodes: FastifyErrorCodes

@@ -107,3 +107,4 @@ export type FastifyHttp2SecureOptions<

onConstructorPoisoning?: ConstructorAction,
logger?: boolean | FastifyLoggerOptions<RawServer> & PinoLoggerOptions | Logger,
logger?: boolean | FastifyLoggerOptions<RawServer> & PinoLoggerOptions,
loggerInstance?: Logger
serializerOpts?: FJSOptions | Record<string, unknown>,

@@ -172,3 +173,3 @@ serverFactory?: FastifyServerFactory<RawServer>,

*/
export type ValidationResult = FastifySchemaValidationError;
export type ValidationResult = FastifySchemaValidationError

@@ -192,4 +193,4 @@ /* Export additional types */

FastifyServerFactory, FastifyServerFactoryHandler, // './types/serverFactory'
FastifyTypeProvider, FastifyTypeProviderDefault, // './types/type-provider'
FastifyErrorCodes, // './types/errors'
FastifyTypeProvider, FastifyTypeProviderDefault, SafePromiseLike, // './types/type-provider'
FastifyErrorCodes // './types/errors'
}

@@ -218,4 +219,4 @@ // named export

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>>

@@ -227,4 +228,4 @@ declare function fastify<

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>>

@@ -236,4 +237,4 @@ declare function fastify<

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>>

@@ -245,4 +246,4 @@ declare function fastify<

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>>

@@ -249,0 +250,0 @@ // CJS export

'use strict'
const VERSION = '4.28.0'
const VERSION = '5.0.0-alpha.2'
const Avvio = require('avvio')
const http = require('node:http')
const diagnostics = require('dc-polyfill')
let lightMyRequest

@@ -35,3 +36,3 @@

const { createServer, compileValidateHTTPVersion } = require('./lib/server')
const { createServer } = require('./lib/server')
const Reply = require('./lib/reply')

@@ -81,2 +82,4 @@ const Request = require('./lib/request')

const initChannel = diagnostics.channel('fastify.initialization')
function defaultBuildPrettyMeta (route) {

@@ -116,3 +119,3 @@ // return a shallow copy of route's sanitized context

const requestIdHeader = (options.requestIdHeader === false) ? false : (options.requestIdHeader || defaultInitOptions.requestIdHeader).toLowerCase()
const requestIdHeader = typeof options.requestIdHeader === 'string' && options.requestIdHeader.length !== 0 ? options.requestIdHeader.toLowerCase() : (options.requestIdHeader === true && 'request-id')
const genReqId = reqIdGenFactory(requestIdHeader, options.genReqId)

@@ -258,4 +261,2 @@ const requestIdLogLabel = options.requestIdLogLabel || 'reqId'

routing: httpHandler,
getDefaultRoute: router.getDefaultRoute.bind(router),
setDefaultRoute: router.setDefaultRoute.bind(router),
// routes shorthand methods

@@ -283,2 +284,35 @@ delete: function _delete (url, options, handler) {

},
propfind: function _propfind (url, options, handler) {
return router.prepareRoute.call(this, { method: 'PROPFIND', url, options, handler })
},
proppatch: function _proppatch (url, options, handler) {
return router.prepareRoute.call(this, { method: 'PROPPATCH', url, options, handler })
},
mkcalendar: function _mkcalendar (url, options, handler) {
return router.prepareRoute.call(this, { method: 'MKCALENDAR', url, options, handler })
},
mkcol: function _mkcol (url, options, handler) {
return router.prepareRoute.call(this, { method: 'MKCOL', url, options, handler })
},
copy: function _copy (url, options, handler) {
return router.prepareRoute.call(this, { method: 'COPY', url, options, handler })
},
move: function _move (url, options, handler) {
return router.prepareRoute.call(this, { method: 'MOVE', url, options, handler })
},
lock: function _lock (url, options, handler) {
return router.prepareRoute.call(this, { method: 'LOCK', url, options, handler })
},
unlock: function _unlock (url, options, handler) {
return router.prepareRoute.call(this, { method: 'UNLOCK', url, options, handler })
},
trace: function _trace (url, options, handler) {
return router.prepareRoute.call(this, { method: 'TRACE', url, options, handler })
},
report: function _mkcalendar (url, options, handler) {
return router.prepareRoute.call(this, { method: 'REPORT', url, options, handler })
},
search: function _search (url, options, handler) {
return router.prepareRoute.call(this, { method: 'SEARCH', url, options, handler })
},
all: function _all (url, options, handler) {

@@ -511,3 +545,2 @@ return router.prepareRoute.call(this, { method: supportedMethods, url, options, handler })

throwIfAlreadyStarted,
validateHTTPVersion: compileValidateHTTPVersion(options),
keepAliveConnections

@@ -519,11 +552,4 @@ })

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 })
}

@@ -530,0 +556,0 @@

// 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":{"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":[{"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},"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 func2 = Object.prototype.hasOwnProperty;

@@ -61,3 +61,3 @@ const pattern0 = new RegExp("idle", "u");

if(data.requestIdHeader === undefined){
data.requestIdHeader = "request-id";
data.requestIdHeader = false;
}

@@ -74,3 +74,3 @@ if(data.requestIdLogLabel === undefined){

if(data.useSemicolonDelimiter === undefined){
data.useSemicolonDelimiter = true;
data.useSemicolonDelimiter = false;
}

@@ -848,4 +848,13 @@ const _errs1 = errors;

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"};
if(typeof data19 !== "boolean"){
let coerced21 = undefined;
if(!(coerced21 !== undefined)){
if(data19 === "false" || data19 === 0 || data19 === null){
coerced21 = false;
}
else if(data19 === "true" || data19 === 1){
coerced21 = 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){

@@ -859,15 +868,23 @@ vErrors = [err12];

}
}
if(coerced21 !== undefined){
data19 = coerced21;
if(data !== undefined){
data["requestIdHeader"] = coerced21;
}
}
}
var _valid3 = _errs59 === errors;
valid6 = valid6 || _valid3;
if(!valid6){
const _errs60 = errors;
const _errs61 = errors;
if(typeof data19 !== "string"){
let dataType21 = typeof data19;
let coerced21 = undefined;
if(!(coerced21 !== undefined)){
if(dataType21 == "number" || dataType21 == "boolean"){
coerced21 = "" + data19;
let dataType22 = typeof data19;
let coerced22 = undefined;
if(!(coerced22 !== undefined)){
if(dataType22 == "number" || dataType22 == "boolean"){
coerced22 = "" + data19;
}
else if(data19 === null){
coerced21 = "";
coerced22 = "";
}

@@ -885,10 +902,10 @@ else {

}
if(coerced21 !== undefined){
data19 = coerced21;
if(coerced22 !== undefined){
data19 = coerced22;
if(data !== undefined){
data["requestIdHeader"] = coerced21;
data["requestIdHeader"] = coerced22;
}
}
}
var _valid3 = _errs60 === errors;
var _valid3 = _errs61 === errors;
valid6 = valid6 || _valid3;

@@ -922,12 +939,12 @@ }

let data20 = data.requestIdLogLabel;
const _errs62 = errors;
const _errs63 = errors;
if(typeof data20 !== "string"){
let dataType22 = typeof data20;
let coerced22 = undefined;
if(!(coerced22 !== undefined)){
if(dataType22 == "number" || dataType22 == "boolean"){
coerced22 = "" + data20;
let dataType23 = typeof data20;
let coerced23 = undefined;
if(!(coerced23 !== undefined)){
if(dataType23 == "number" || dataType23 == "boolean"){
coerced23 = "" + data20;
}
else if(data20 === null){
coerced22 = "";
coerced23 = "";
}

@@ -939,20 +956,20 @@ else {

}
if(coerced22 !== undefined){
data20 = coerced22;
if(coerced23 !== undefined){
data20 = coerced23;
if(data !== undefined){
data["requestIdLogLabel"] = coerced22;
data["requestIdLogLabel"] = coerced23;
}
}
}
var valid0 = _errs62 === errors;
var valid0 = _errs63 === errors;
if(valid0){
let data21 = data.http2SessionTimeout;
const _errs64 = errors;
const _errs65 = 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 dataType24 = typeof data21;
let coerced24 = undefined;
if(!(coerced24 !== undefined)){
if(dataType24 === "boolean" || data21 === null
|| (dataType24 === "string" && data21 && data21 == +data21 && !(data21 % 1))){
coerced24 = +data21;
}

@@ -964,21 +981,21 @@ else {

}
if(coerced23 !== undefined){
data21 = coerced23;
if(coerced24 !== undefined){
data21 = coerced24;
if(data !== undefined){
data["http2SessionTimeout"] = coerced23;
data["http2SessionTimeout"] = coerced24;
}
}
}
var valid0 = _errs64 === errors;
var valid0 = _errs65 === errors;
if(valid0){
let data22 = data.exposeHeadRoutes;
const _errs66 = errors;
const _errs67 = errors;
if(typeof data22 !== "boolean"){
let coerced24 = undefined;
if(!(coerced24 !== undefined)){
let coerced25 = undefined;
if(!(coerced25 !== undefined)){
if(data22 === "false" || data22 === 0 || data22 === null){
coerced24 = false;
coerced25 = false;
}
else if(data22 === "true" || data22 === 1){
coerced24 = true;
coerced25 = true;
}

@@ -990,21 +1007,21 @@ else {

}
if(coerced24 !== undefined){
data22 = coerced24;
if(coerced25 !== undefined){
data22 = coerced25;
if(data !== undefined){
data["exposeHeadRoutes"] = coerced24;
data["exposeHeadRoutes"] = coerced25;
}
}
}
var valid0 = _errs66 === errors;
var valid0 = _errs67 === errors;
if(valid0){
let data23 = data.useSemicolonDelimiter;
const _errs68 = errors;
const _errs69 = errors;
if(typeof data23 !== "boolean"){
let coerced25 = undefined;
if(!(coerced25 !== undefined)){
let coerced26 = undefined;
if(!(coerced26 !== undefined)){
if(data23 === "false" || data23 === 0 || data23 === null){
coerced25 = false;
coerced26 = false;
}
else if(data23 === "true" || data23 === 1){
coerced25 = true;
coerced26 = true;
}

@@ -1016,15 +1033,15 @@ else {

}
if(coerced25 !== undefined){
data23 = coerced25;
if(coerced26 !== undefined){
data23 = coerced26;
if(data !== undefined){
data["useSemicolonDelimiter"] = coerced25;
data["useSemicolonDelimiter"] = coerced26;
}
}
}
var valid0 = _errs68 === errors;
var valid0 = _errs69 === errors;
if(valid0){
if(data.versioning !== undefined){
let data24 = data.versioning;
const _errs70 = errors;
if(errors === _errs70){
const _errs71 = errors;
if(errors === _errs71){
if(data24 && typeof data24 == "object" && !Array.isArray(data24)){

@@ -1042,3 +1059,3 @@ let missing1;

}
var valid0 = _errs70 === errors;
var valid0 = _errs71 === errors;
}

@@ -1051,9 +1068,9 @@ else {

let data25 = data.constraints;
const _errs73 = errors;
if(errors === _errs73){
const _errs74 = errors;
if(errors === _errs74){
if(data25 && typeof data25 == "object" && !Array.isArray(data25)){
for(const key2 in data25){
let data26 = data25[key2];
const _errs76 = errors;
if(errors === _errs76){
const _errs77 = errors;
if(errors === _errs77){
if(data26 && typeof data26 == "object" && !Array.isArray(data26)){

@@ -1069,10 +1086,10 @@ let missing2;

if(typeof data27 !== "string"){
let dataType26 = typeof data27;
let coerced26 = undefined;
if(!(coerced26 !== undefined)){
if(dataType26 == "number" || dataType26 == "boolean"){
coerced26 = "" + data27;
let dataType27 = typeof data27;
let coerced27 = undefined;
if(!(coerced27 !== undefined)){
if(dataType27 == "number" || dataType27 == "boolean"){
coerced27 = "" + data27;
}
else if(data27 === null){
coerced26 = "";
coerced27 = "";
}

@@ -1084,6 +1101,6 @@ else {

}
if(coerced26 !== undefined){
data27 = coerced26;
if(coerced27 !== undefined){
data27 = coerced27;
if(data26 !== undefined){
data26["name"] = coerced26;
data26["name"] = coerced27;
}

@@ -1100,3 +1117,3 @@ }

}
var valid7 = _errs76 === errors;
var valid7 = _errs77 === errors;
if(!valid7){

@@ -1112,3 +1129,3 @@ break;

}
var valid0 = _errs73 === errors;
var valid0 = _errs74 === errors;
}

@@ -1154,2 +1171,3 @@ else {

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,"jsonShorthand":true,"ignoreTrailingSlash":false,"ignoreDuplicateSlashes":false,"maxParamLength":100,"onProtoPoisoning":"error","onConstructorPoisoning":"error","pluginTimeout":10000,"requestIdHeader":false,"requestIdLogLabel":"reqId","http2SessionTimeout":72000,"exposeHeadRoutes":true,"useSemicolonDelimiter":false}
/* c8 ignore stop */

@@ -5,3 +5,2 @@ 'use strict'

const { FifoMap: Fifo } = require('toad-cache')
const { safeParse: safeParseContentType, defaultContentType } = require('fast-content-type-parse')
const secureJson = require('secure-json-parse')

@@ -31,2 +30,3 @@ const {

} = require('./errors')
const { FSTSEC001 } = require('./warnings')

@@ -39,3 +39,3 @@ function ContentTypeParser (bodyLimit, onProtoPoisoning, onConstructorPoisoning) {

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 = []

@@ -48,6 +48,13 @@ this.cache = new Fifo(100)

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)) {

@@ -70,12 +77,13 @@ throw new FST_ERR_CTP_ALREADY_PRESENT(contentType)

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)
}

@@ -85,3 +93,10 @@ }

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)
}

@@ -101,23 +116,16 @@

ContentTypeParser.prototype.getParser = function (contentType) {
if (this.hasParser(contentType)) {
return this.customParsers.get(contentType)
}
let parser = this.customParsers.get(contentType)
if (parser !== undefined) return parser
const parser = this.cache.get(contentType)
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 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 (
contentType.slice(0, parserListItem.length) === parserListItem &&
(contentType.length === parserListItem.length || contentType.charCodeAt(parserListItem.length) === 59 /* `;` */ || contentType.charCodeAt(parserListItem.length) === 32 /* ` ` */)
) {
parser = this.customParsers.get(parserListItem)
this.cache.set(contentType, parser)

@@ -131,5 +139,4 @@ return parser

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)

@@ -151,10 +158,16 @@ return parser

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 removed = this.customParsers.delete(contentType)
const idx = parsers.findIndex(ct => ct.toString() === contentType)
const idx = parsers.findIndex(ct => ct.toString() === contentType.toString())
if (idx > -1) {

@@ -194,3 +207,3 @@ parsers.splice(idx, 1)

if (result && typeof result.then === 'function') {
if (typeof result?.then === 'function') {
result.then(body => done(null, body), done)

@@ -218,5 +231,3 @@ }

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'])

@@ -387,56 +398,11 @@ if (contentLength > limit) {

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

@@ -443,0 +409,0 @@ module.exports.helpers = {

'use strict'
/* eslint no-prototype-builtins: 0 */
const {

@@ -16,7 +14,6 @@ kReply,

FST_ERR_DEC_AFTER_START,
FST_ERR_DEC_REFERENCE_TYPE,
FST_ERR_DEC_DEPENDENCY_INVALID_TYPE
} = require('./errors')
const { FSTDEP006 } = require('./warnings')
function decorate (instance, name, fn, dependencies) {

@@ -62,3 +59,3 @@ if (Object.prototype.hasOwnProperty.call(instance, name)) {

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)
}

@@ -107,4 +104,3 @@ }

// 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])) {

@@ -111,0 +107,0 @@ throw new FST_ERR_DEC_MISSING_DEPENDENCY(deps[i])

// This file is autogenerated by build/build-error-serializer.js, do not edit
/* istanbul ignore file */
/* c8 ignore start */

@@ -120,1 +120,2 @@ 'use strict'

}(validator, serializer)
/* c8 ignore stop */

@@ -154,2 +154,6 @@ 'use strict'

),
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."
),

@@ -213,2 +217,23 @@ /**

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
),
/**

@@ -344,8 +369,2 @@ * reply

),
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(

@@ -435,2 +454,8 @@ 'FST_ERR_INVALID_URL',

),
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
),

@@ -437,0 +462,0 @@ /**

'use strict'
const { bodylessMethods, bodyMethods } = require('./httpMethods')
const diagnostics = require('dc-polyfill')
const { validate: validateSchema } = require('./validation')

@@ -8,5 +10,8 @@ const { preValidationHookRunner, preHandlerHookRunner } = require('./hooks')

kReplyIsError,
kRouteContext
kRouteContext,
kFourOhFourContext
} = require('./symbols')
const channels = diagnostics.tracingChannel('fastify.request.handler')
function handleRequest (err, request, reply) {

@@ -24,3 +29,3 @@ if (reply.sent === true) return

if (method === 'GET' || method === 'HEAD') {
if (bodylessMethods.has(method)) {
handler(request, reply)

@@ -30,11 +35,13 @@ return

const contentType = headers['content-type']
if (bodyMethods.has(method)) {
const contentType = headers['content-type']
const contentLength = headers['content-length']
const transferEncoding = headers['transfer-encoding']
if (method === 'POST' || method === 'PUT' || method === 'PATCH' || method === 'TRACE' || method === 'SEARCH' ||
method === 'PROPFIND' || method === 'PROPPATCH' || method === 'LOCK' || 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
(contentLength === undefined || contentLength === '0') &&
transferEncoding === undefined
) {
// Request has no body to parse
handler(request, reply)

@@ -45,2 +52,7 @@ } else {

} else {
if (contentLength === undefined && transferEncoding === undefined && method === 'OPTIONS') {
// OPTIONS can have a Content-Type header without a body
handler(request, reply)
return
}
context.contentTypeParser.run(contentType, handler, request, reply)

@@ -51,17 +63,2 @@ }

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

@@ -134,24 +131,58 @@ handler(request, reply)

if (err != null) {
reply[kReplyIsError] = true
reply.send(err)
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)
}
}
let result
function preHandlerCallbackInner (err, request, reply, store) {
const context = request[kRouteContext]
try {
result = request[kRouteContext].handler(request, reply)
} catch (err) {
reply[kReplyIsError] = true
reply.send(err)
return
}
if (err != null) {
reply[kReplyIsError] = true
reply.send(err)
if (store) {
store.error = err
channels.error.publish(store)
}
return
}
if (result !== undefined) {
if (result !== null && typeof result.then === 'function') {
wrapThenable(result, reply)
} else {
reply.send(result)
let result
try {
result = context.handler(request, reply)
} catch (err) {
if (store) {
store.error = 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)
}

@@ -158,0 +189,0 @@ }

'use strict'
const bodylessMethods = new Set([
// Standard
'GET',
'HEAD',
'TRACE',
// WebDAV
'UNLOCK'
])
const bodyMethods = new Set([
// Standard
'DELETE',
'OPTIONS',
'PATCH',
'PUT',
'POST',
// WebDAV
'COPY',
'LOCK',
'MOVE',
'MKCOL',
'PROPFIND',
'PROPPATCH',
'REPORT',
'SEARCH',
'MKCALENDAR'
])
module.exports = {
bodylessMethods,
bodyMethods,
supportedMethods: [
'DELETE',
'GET',
'HEAD',
'PATCH',
'POST',
'PUT',
'OPTIONS',
'PROPFIND',
'PROPPATCH',
'MKCOL',
'COPY',
'MOVE',
'LOCK',
'UNLOCK',
'TRACE',
'SEARCH',
'REPORT',
'MKCALENDAR'
...bodylessMethods,
...bodyMethods
]
}

@@ -14,3 +14,6 @@ 'use strict'

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_CONFIG,
FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED
} = require('./errors')

@@ -55,3 +58,3 @@

version: req.headers && req.headers['accept-version'],
hostname: req.hostname,
host: req.host,
remoteAddress: req.ip,

@@ -75,3 +78,4 @@ remotePort: req.socket ? req.socket.remotePort : undefined

function createLogger (options) {
if (!options.logger) {
// if no logger is provided, then create a default logger
if (!options.loggerInstance && !options.logger) {
const logger = nullLogger

@@ -82,6 +86,11 @@ logger.child = () => logger

if (validateLogger(options.logger)) {
if (options.logger && options.loggerInstance) {
throw new FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED()
}
// check if the logger instance has all required properties
if (validateLogger(options.loggerInstance)) {
const logger = createPinoLogger({
logger: options.logger,
serializers: Object.assign({}, serializers, options.logger.serializers)
logger: options.loggerInstance,
serializers: Object.assign({}, serializers, options.loggerInstance.serializers)
})

@@ -91,2 +100,11 @@ 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 = {}

@@ -93,0 +111,0 @@ if (Object.prototype.toString.call(options.logger) === '[object Object]') {

@@ -12,5 +12,5 @@ 'use strict'

FST_ERR_PLUGIN_VERSION_MISMATCH,
FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE
FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE,
FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER
} = require('./errors')
const { FSTWRN002 } = require('./warnings.js')

@@ -110,7 +110,7 @@ function getMeta (fn) {

const meta = getMeta(fn)
if (!meta) return
if (meta == null || meta?.fastify == null) return
const requiredVersion = meta.fastify
const fastifyRc = /-rc.+$/.test(this.version)
const fastifyRc = /-(rc|pre|alpha).+$/.test(this.version)
if (fastifyRc === true && semver.gt(this.version, semver.coerce(requiredVersion)) === true) {

@@ -143,3 +143,3 @@ // A Fastify release candidate phase is taking place. In order to reduce

if (fn.constructor.name === 'AsyncFunction' && fn.length === 3) {
FSTWRN002(pluginName || 'anonymous')
throw new FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER(pluginName)
}

@@ -146,0 +146,0 @@ }

@@ -58,3 +58,3 @@ 'use strict'

} = require('./errors')
const { FSTDEP010, FSTDEP013, FSTDEP019, FSTDEP020, FSTDEP021 } = require('./warnings')
const { FSTDEP010, FSTDEP013, FSTDEP019, FSTDEP021 } = require('./warnings')

@@ -141,2 +141,7 @@ const toString = Object.prototype.toString

Reply.prototype.writeEarlyHints = function (hints, callback) {
this.raw.writeEarlyHints(hints, callback)
return this
}
Reply.prototype.hijack = function () {

@@ -482,9 +487,2 @@ this[kReplyHijacked] = true

// 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.

@@ -916,5 +914,4 @@ // See

// eslint-disable-next-line no-var
var prop
// eslint-disable-next-line no-var
for (var i = 0; i < props.length; i++) {

@@ -921,0 +918,0 @@ prop = props[i]

'use strict'
const proxyAddr = require('proxy-addr')
const semver = require('semver')
const {

@@ -52,4 +51,4 @@ FSTDEP005,

if (tp === true) {
// Support plain true/false
return function () { return true }
// Support trusting everything
return null
}

@@ -119,3 +118,4 @@ if (typeof tp === 'number') {

get () {
return proxyAddr(this.raw, proxyFn)
const addrs = proxyAddr.all(this.raw, proxyFn)
return addrs[addrs.length - 1]
}

@@ -128,3 +128,3 @@ },

},
hostname: {
host: {
get () {

@@ -244,6 +244,3 @@ if (this.ip !== undefined && this.headers['x-forwarded-host']) {

get () {
/* istanbul ignore next */
if (semver.gte(process.versions.node, '13.0.0')) {
FSTDEP005()
}
FSTDEP005()
return this.raw.connection

@@ -264,3 +261,3 @@ }

},
hostname: {
host: {
get () {

@@ -270,2 +267,23 @@ return this.raw.headers.host || this.raw.headers[':authority']

},
hostname: {
get () {
return (this.host).split(':')[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 portFromHeader = parseInt((this.headers.host || this.headers[':authority']).split(':').slice(-1)[0])
if (!isNaN(portFromHeader)) {
return portFromHeader
}
// fall back to null
return null
}
},
protocol: {

@@ -308,9 +326,9 @@ get () {

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
)

@@ -352,4 +370,4 @@ const validateFn = validatorCompiler({

if (validate == null && (schema == null ||
typeof schema !== 'object' ||
Array.isArray(schema))
typeof schema !== 'object' ||
Array.isArray(schema))
) {

@@ -356,0 +374,0 @@ throw new FST_ERR_REQ_INVALID_VALIDATION_INVOCATION(httpPart)

@@ -12,4 +12,3 @@ 'use strict'

FSTDEP007,
FSTDEP008,
FSTDEP014
FSTDEP008
} = require('./warnings')

@@ -25,3 +24,2 @@

FST_ERR_SCH_SERIALIZATION_BUILD,
FST_ERR_DEFAULT_ROUTE_INVALID_TYPE,
FST_ERR_DUPLICATED_ROUTE,

@@ -77,3 +75,2 @@ FST_ERR_INVALID_URL,

let globalExposeHeadRoutes
let validateHTTPVersion
let keepAliveConnections

@@ -95,3 +92,2 @@

throwIfAlreadyStarted = fastifyArgs.throwIfAlreadyStarted
validateHTTPVersion = fastifyArgs.validateHTTPVersion

@@ -109,14 +105,2 @@ globalExposeHeadRoutes = options.exposeHeadRoutes

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,

@@ -177,6 +161,7 @@ closeRoutes: () => { closing = true },

const normalizedMethod = options.method?.toUpperCase() ?? ''
return findRoute({
...options,
method: normalizedMethod
}) !== null
return router.hasRoute(
normalizedMethod,
options.url || '',
options.constraints
)
}

@@ -469,15 +454,2 @@

// 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
}
if (closing === true) {

@@ -484,0 +456,0 @@ /* istanbul ignore next mac, windows */

@@ -6,4 +6,4 @@ 'use strict'

const dns = require('node:dns')
const os = require('node:os')
const { FSTDEP011 } = require('./warnings')
const { kState, kOptions, kServerBindings } = require('./symbols')

@@ -19,3 +19,2 @@ const { onListenHookRunner } = require('./hooks')

module.exports.createServer = createServer
module.exports.compileValidateHTTPVersion = compileValidateHTTPVersion

@@ -30,23 +29,7 @@ function defaultResolveServerListeningText (address) {

// `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') {
listenOptions.cb = cb

@@ -226,2 +209,3 @@ }

server.removeListener('error', wrap)
server.removeListener('listening', wrap)
if (!err) {

@@ -247,3 +231,4 @@ const address = logServerAddress.call(this, server, listenOptions.listenTextResolver || defaultResolveServerListeningText)

if (!this[kState].closing) {
server.listen(listenOptions, wrap)
server.once('listening', wrap)
server.listen(listenOptions)
this[kState].listening = true

@@ -263,4 +248,10 @@ }

let errEventHandler
let listeningEventHandler
function cleanup () {
server.removeListener('error', errEventHandler)
server.removeListener('listening', listeningEventHandler)
}
const errEvent = new Promise((resolve, reject) => {
errEventHandler = (err) => {
cleanup()
this[kState].listening = false

@@ -271,14 +262,16 @@ reject(err)

})
const listen = new Promise((resolve, reject) => {
server.listen(listenOptions, () => {
server.removeListener('error', errEventHandler)
const listeningEvent = new Promise((resolve, reject) => {
listeningEventHandler = () => {
cleanup()
this[kState].listening = true
resolve(logServerAddress.call(this, server, listenOptions.listenTextResolver || defaultResolveServerListeningText))
})
// we set it afterwards because listen can throw
this[kState].listening = true
}
server.once('listening', listeningEventHandler)
})
server.listen(listenOptions)
return Promise.race([
errEvent, // e.g invalid port range error is always emitted before the server listening
listen
listeningEvent
])

@@ -288,52 +281,2 @@ })

/**
* 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) {

@@ -375,53 +318,49 @@ let server = null

}
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
return [address.address]
}
function normalizePort (firstArg) {
const port = Number(firstArg)
return port >= 0 && !Number.isNaN(port) && Number.isInteger(port) ? port : 0
}
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()]
}
/* istanbul ignore next */
address = (isUnixSocket ? '' : ('http' + (this[kOptions].https ? 's' : '') + '://')) + address
const serverListeningText = listenTextResolver(address)
this.log.info(serverListeningText)
return address
for (const address of addresses) {
this.log.info(listenTextResolver(address))
}
return addresses[0]
}

@@ -428,0 +367,0 @@

@@ -5,2 +5,21 @@ 'use strict'

/**
* Deprecation codes:
* - FSTDEP005
* - FSTDEP007
* - FSTDEP008
* - FSTDEP009
* - FSTDEP010
* - FSTDEP012
* - FSTDEP013
* - FSTDEP015
* - FSTDEP016
* - FSTDEP017
* - FSTDEP018
* - FSTDEP019
* - FSTDEP021
* - FSTWRN001
* - FSTSEC001
*/
const FSTDEP005 = createDeprecation({

@@ -11,7 +30,2 @@ code: 'FSTDEP005',

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({

@@ -37,7 +51,2 @@ code: 'FSTDEP007',

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({

@@ -53,7 +62,2 @@ code: 'FSTDEP012',

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({

@@ -84,7 +88,2 @@ code: 'FSTDEP015',

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({

@@ -102,6 +101,6 @@ code: 'FSTDEP021',

const FSTWRN002 = 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`',
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

@@ -112,3 +111,2 @@ })

FSTDEP005,
FSTDEP006,
FSTDEP007,

@@ -118,6 +116,4 @@ FSTDEP008,

FSTDEP010,
FSTDEP011,
FSTDEP012,
FSTDEP013,
FSTDEP014,
FSTDEP015,

@@ -128,6 +124,5 @@ FSTDEP016,

FSTDEP019,
FSTDEP020,
FSTDEP021,
FSTWRN001,
FSTWRN002
FSTSEC001
}

@@ -8,3 +8,7 @@ 'use strict'

function wrapThenable (thenable, reply) {
const diagnostics = require('dc-polyfill')
const channels = diagnostics.tracingChannel('fastify.request.handler')
function wrapThenable (thenable, reply, store) {
if (store) store.async = true
thenable.then(function (payload) {

@@ -15,29 +19,44 @@ if (reply[kReplyHijacked] === true) {

// 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)
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)) {
// 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 (reply.sent === true) {
reply.log.error({ err }, 'Promise errored, but reply.sent = true was set')
return
if (store) {
store.error = err
channels.error.publish(store) // note that error happens before asyncStart
channels.asyncStart.publish(store)
}
reply[kReplyIsError] = true
try {
if (reply.sent === true) {
reply.log.error({ err }, 'Promise errored, but reply.sent = true was set')
return
}
// try-catch allow to re-throw error in error handler for async handler
try {
reply[kReplyIsError] = true
reply.send(err)

@@ -47,3 +66,8 @@ // The following should not happen

} 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)
}
}

@@ -50,0 +74,0 @@ })

{
"name": "fastify",
"version": "4.28.0",
"version": "5.0.0-alpha.2",
"description": "Fast and low overhead web framework, for Node.js",

@@ -14,20 +14,18 @@ "main": "fastify.js",

"coverage": "npm run unit -- --coverage-report=html",
"coverage:ci": "c8 --reporter=lcov tap --coverage-report=html --no-browser --no-check-coverage",
"coverage:ci-check-coverage": "c8 check-coverage --branches 100 --functions 100 --lines 100 --statements 100",
"lint": "npm run lint:standard && npm run lint:typescript && npm run lint:markdown",
"lint:fix": "standard --fix && npm run lint:typescript:fix",
"coverage:ci": "tap --coverage-report=html --coverage-report=lcov --allow-incomplete-coverage",
"coverage:ci-check-coverage": "tap replay",
"lint": "npm run lint:eslint",
"lint:fix": "eslint --fix",
"lint:markdown": "markdownlint-cli2",
"lint:standard": "standard | snazzy",
"lint:typescript": "eslint -c types/.eslintrc.json types/**/*.d.ts test/types/**/*.test-d.ts",
"lint:typescript:fix": "npm run lint:typescript -- --fix",
"prepublishOnly": "cross-env PREPUBLISH=true tap --no-check-coverage test/build/**.test.js && npm run test:validator:integrity",
"lint:eslint": "eslint",
"prepublishOnly": "cross-env PREPUBLISH=true tap --allow-incomplete-coverage test/build/**.test.js && npm run test:validator:integrity",
"test": "npm run lint && npm run unit && npm run test:typescript",
"test:ci": "npm run unit -- --cov --coverage-report=lcovonly && npm run test:typescript",
"test:ci": "npm run unit -- --coverage-report=lcovonly && npm run test:typescript",
"test:report": "npm run lint && npm run unit:report && npm run test:typescript",
"test:validator:integrity": "npm run build:validation && git diff --quiet --ignore-all-space --ignore-blank-lines --ignore-cr-at-eol lib/error-serializer.js && git diff --quiet --ignore-all-space --ignore-blank-lines --ignore-cr-at-eol lib/configValidator.js",
"test:typescript": "tsc test/types/import.ts && tsd",
"test:watch": "npm run unit -- --watch --cov --no-coverage-report --reporter=terse",
"unit": "c8 tap",
"test:watch": "npm run unit -- --watch --coverage-report=none --reporter=terse",
"unit": "tap",
"unit:junit": "tap-mocha-reporter xunit < out.tap > test/junit-testresults.xml",
"unit:report": "tap --cov --coverage-report=html --coverage-report=cobertura | tee out.tap",
"unit:report": "tap --coverage-report=html --coverage-report=cobertura | tee out.tap",
"citgm": "tap --jobs=1 --timeout=120"

@@ -157,34 +155,28 @@ },

"devDependencies": {
"@fastify/pre-commit": "^2.0.2",
"@sinclair/typebox": "^0.31.17",
"@sinonjs/fake-timers": "^11.1.0",
"@types/node": "^20.8.4",
"@typescript-eslint/eslint-plugin": "^6.7.5",
"@typescript-eslint/parser": "^6.7.5",
"@fastify/pre-commit": "^2.1.0",
"@sinclair/typebox": "^0.32.22",
"@sinonjs/fake-timers": "^11.2.2",
"@stylistic/eslint-plugin": "^2.1.0",
"@stylistic/eslint-plugin-js": "^2.1.0",
"@types/node": "^20.12.7",
"ajv": "^8.12.0",
"ajv-errors": "^3.0.0",
"ajv-formats": "^2.1.1",
"ajv-formats": "^3.0.1",
"ajv-i18n": "^4.2.0",
"ajv-merge-patch": "^5.0.1",
"autocannon": "^7.14.0",
"autocannon": "^7.15.0",
"branch-comparer": "^1.1.0",
"c8": "^8.0.1",
"concurrently": "^8.2.2",
"cross-env": "^7.0.3",
"eslint": "^8.51.0",
"eslint-config-standard": "^17.1.0",
"eslint-import-resolver-node": "^0.3.9",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-n": "^16.2.0",
"eslint-plugin-promise": "^6.1.1",
"eslint": "^9.0.0",
"fast-json-body": "^1.1.0",
"fastify-plugin": "^4.5.1",
"fluent-json-schema": "^4.1.2",
"form-data": "^4.0.0",
"fluent-json-schema": "^4.2.1",
"h2url": "^0.2.0",
"http-errors": "^2.0.0",
"joi": "^17.11.0",
"json-schema-to-ts": "^2.9.2",
"joi": "^17.12.3",
"json-schema-to-ts": "^3.0.1",
"JSONStream": "^1.3.5",
"markdownlint-cli2": "^0.10.0",
"markdownlint-cli2": "^0.13.0",
"neostandard": "^0.7.0",
"node-forge": "^1.3.1",

@@ -194,40 +186,28 @@ "proxyquire": "^2.1.3",

"simple-get": "^4.0.1",
"snazzy": "^9.0.0",
"split2": "^4.2.0",
"standard": "^17.1.0",
"tap": "^16.3.9",
"tsd": "^0.29.0",
"typescript": "^5.2.2",
"undici": "^5.26.0",
"tap": "^19.0.0",
"tsd": "^0.31.0",
"typescript": "^5.4.5",
"undici": "^6.13.0",
"vary": "^1.1.2",
"yup": "^1.3.2"
"yup": "^1.4.0"
},
"dependencies": {
"@fastify/ajv-compiler": "^3.5.0",
"@fastify/error": "^3.4.0",
"@fastify/error": "^3.4.1",
"@fastify/fast-json-stringify-compiler": "^4.3.0",
"abstract-logging": "^2.0.1",
"avvio": "^8.3.0",
"fast-content-type-parse": "^1.1.0",
"fast-json-stringify": "^5.8.0",
"find-my-way": "^8.0.0",
"light-my-request": "^5.11.0",
"dc-polyfill": "^0.1.6",
"fast-json-stringify": "^5.14.1",
"find-my-way": "^8.1.0",
"light-my-request": "^5.13.0",
"pino": "^9.0.0",
"process-warning": "^3.0.0",
"proxy-addr": "^2.0.7",
"rfdc": "^1.3.0",
"rfdc": "^1.3.1",
"secure-json-parse": "^2.7.0",
"semver": "^7.5.4",
"toad-cache": "^3.3.0"
"semver": "^7.6.0",
"toad-cache": "^3.7.0"
},
"standard": {
"ignore": [
"lib/configValidator.js",
"lib/error-serializer.js",
"fastify.d.ts",
"types/*",
"test/types/*",
"test/same-shape.test.js"
]
},
"tsd": {

@@ -234,0 +214,0 @@ "directory": "test/types"

@@ -17,3 +17,3 @@ <div align="center"> <a href="https://fastify.dev/">

SIte](https://github.com/fastify/fastify/workflows/website/badge.svg?branch=main)](https://github.com/fastify/fastify/actions/workflows/website.yml)
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://standardjs.com/)
[![neostandard javascript style](https://img.shields.io/badge/code_style-neostandard-brightgreen?style=flat)](https://github.com/neostandard/neostandard)
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/7585/badge)](https://bestpractices.coreinfrastructure.org/projects/7585)

@@ -50,7 +50,5 @@

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, which is not released/LTS yet.
Check out the [`4.x` branch](https://github.com/fastify/fastify/tree/4.x) for `v4`.
### Table of Contents

@@ -61,3 +59,2 @@

- [Example](#example)
- [Fastify v1.x and v2.x](#fastify-v1x-and-v2x)
- [Core features](#core-features)

@@ -64,0 +61,0 @@ - [Benchmarks](#benchmarks)

@@ -9,3 +9,2 @@ 'use strict'

const split = require('split2')
const FormData = require('form-data')
const Fastify = require('..')

@@ -72,17 +71,14 @@ const { getServerUrl } = require('./helper')

test('using post method and multipart/formdata', t => {
test('using post method and multipart/formdata', async t => {
t.plan(3)
const form = FormData()
form.append('test-field', 'just some field')
const form = new FormData()
form.set('test-field', 'just some field')
sget({
const response = await fetch(getServerUrl(fastify) + '/notSupported', {
method: 'POST',
url: getServerUrl(fastify) + '/notSupported',
body: form,
json: false
}, (err, response, body) => {
t.error(err)
t.equal(response.statusCode, 404)
t.equal(response.headers['content-type'], 'application/json; charset=utf-8')
body: form
})
t.equal(response.status, 404)
t.equal(response.statusText, 'Not Found')
t.equal(response.headers.get('content-type'), 'application/json; charset=utf-8')
})

@@ -89,0 +85,0 @@ })

@@ -27,4 +27,24 @@ 'use strict'

const optsWithHostnameAndPort = {
schema: {
response: {
'2xx': {
type: 'object',
properties: {
hello: {
type: 'string'
},
hostname: {
type: 'string'
},
port: {
type: 'string'
}
}
}
}
}
}
test('async await', t => {
t.plan(11)
t.plan(13)
const fastify = Fastify()

@@ -50,2 +70,12 @@ try {

try {
fastify.get('/await/hostname_port', optsWithHostnameAndPort, async function awaitMyFunc (req, reply) {
await sleep(200)
return { hello: 'world', hostname: req.hostname, port: req.port }
})
t.pass()
} catch (e) {
t.fail()
}
fastify.listen({ port: 0 }, err => {

@@ -74,2 +104,16 @@ t.error(err)

})
t.test('test for hostname and port in request', t => {
t.plan(4)
sget({
method: 'GET',
url: 'http://localhost:' + fastify.server.address().port + '/await/hostname_port'
}, (err, response, body) => {
t.error(err)
t.equal(response.statusCode, 200)
const parsedBody = JSON.parse(body)
t.equal(parsedBody.hostname, 'localhost')
t.equal(parseInt(parsedBody.port), fastify.server.address().port)
})
})
})

@@ -141,3 +185,3 @@ })

const fastify = Fastify({
logger
loggerInstance: logger
})

@@ -144,0 +188,0 @@

@@ -7,2 +7,3 @@ 'use strict'

const path = require('node:path')
const { loadESLint } = require('eslint')

@@ -19,4 +20,5 @@ const { code } = require('../../build/build-error-serializer')

// standard is a esm, we import it like this
const { default: standard } = await import('standard')
const result = await standard.lintText(code)
const Eslint = await loadESLint({ useFlatConfig: true })
const eslint = new Eslint()
const result = await eslint.lintText(code)

@@ -23,0 +25,0 @@ // if there are any invalid syntax

@@ -7,3 +7,2 @@ 'use strict'

const { Client } = require('undici')
const semver = require('semver')

@@ -40,42 +39,4 @@ test('Should return 503 while closing - pipelining', async t => {

// default enable of idle closing idle connection is accidentally backported to 18.19.0 and fixed in 18.20.3
// Refs: https://github.com/nodejs/node/releases/tag/v18.20.3
const isNodeDefaultClosingIdleConnection =
(
semver.gte(process.version, '18.19.0') &&
semver.lt(process.version, '18.20.3')
) ||
semver.gte(process.version, '19.0.0')
test('Should not return 503 while closing - pipelining - return503OnClosing: false, skip when Node default closing idle connection', { skip: isNodeDefaultClosingIdleConnection }, async t => {
const fastify = Fastify({
return503OnClosing: false,
forceCloseConnections: false
})
fastify.get('/', (req, reply) => {
fastify.close()
reply.send({ hello: 'world' })
})
await fastify.listen({ port: 0 })
const instance = new Client('http://localhost:' + fastify.server.address().port, {
pipelining: 2
})
const codes = [200, 200, 200]
const responses = await Promise.all([
instance.request({ path: '/', method: 'GET' }),
instance.request({ path: '/', method: 'GET' }),
instance.request({ path: '/', method: 'GET' })
])
const actual = responses.map(r => r.statusCode)
t.same(actual, codes)
await instance.close()
})
test('Should close the socket abruptly - pipelining - return503OnClosing: false, skip when Node not default closing idle connection', { skip: !isNodeDefaultClosingIdleConnection }, async t => {
// Since Node v19, we will always invoke server.closeIdleConnections()
test('Should close the socket abruptly - pipelining - return503OnClosing: false', async t => {
// Since Node v20, we will always invoke server.closeIdleConnections()
// therefore our socket will be closed

@@ -82,0 +43,0 @@ const fastify = Fastify({

@@ -8,3 +8,2 @@ 'use strict'

const { Client } = require('undici')
const semver = require('semver')
const split = require('split2')

@@ -208,42 +207,3 @@ const { sleep } = require('./helper')

const isNodeVersionGte1819 = semver.gte(process.version, '18.19.0')
test('Current opened connection should continue to work after closing and return "connection: close" header - return503OnClosing: false, skip Node >= v18.19.x', { skip: isNodeVersionGte1819 }, t => {
const fastify = Fastify({
return503OnClosing: false,
forceCloseConnections: false
})
fastify.get('/', (req, reply) => {
fastify.close()
reply.send({ hello: 'world' })
})
fastify.listen({ port: 0 }, err => {
t.error(err)
const port = fastify.server.address().port
const client = net.createConnection({ port }, () => {
client.write('GET / HTTP/1.1\r\nHost: example.com\r\n\r\n')
client.once('data', data => {
t.match(data.toString(), /Connection:\s*keep-alive/i)
t.match(data.toString(), /200 OK/i)
client.write('GET / HTTP/1.1\r\nHost: example.com\r\n\r\n')
client.once('data', data => {
t.match(data.toString(), /Connection:\s*close/i)
t.match(data.toString(), /200 OK/i)
// Test that fastify closes the TCP connection
client.once('close', () => {
t.end()
})
})
})
})
})
})
test('Current opened connection should NOT continue to work after closing and return "connection: close" header - return503OnClosing: false, skip Node < v18.19.x', { skip: !isNodeVersionGte1819 }, t => {
test('Current opened connection should NOT continue to work after closing and return "connection: close" header - return503OnClosing: false', t => {
t.plan(4)

@@ -250,0 +210,0 @@ const fastify = Fastify({

@@ -15,3 +15,3 @@ 'use strict'

test('should know about internal parsers', t => {
t.plan(4)
t.plan(5)

@@ -23,2 +23,3 @@ const fastify = Fastify()

t.ok(fastify.hasContentTypeParser('text/plain'))
t.ok(fastify.hasContentTypeParser(' text/plain '))
t.notOk(fastify.hasContentTypeParser('application/jsoff'))

@@ -28,4 +29,4 @@ })

test('should work with string and RegExp', t => {
t.plan(7)
test('should only work with string and RegExp', t => {
t.plan(8)

@@ -44,2 +45,3 @@ const fastify = Fastify()

t.notOk(fastify.hasContentTypeParser('*'))
t.throws(() => fastify.hasContentTypeParser(123), FST_ERR_CTP_INVALID_TYPE)
})

@@ -52,3 +54,3 @@

test('should return matching parser', t => {
t.plan(3)
t.plan(6)

@@ -64,5 +66,8 @@ const fastify = Fastify()

t.equal(fastify[keys.kContentTypeParser].getParser('text/html').fn, third)
t.equal(fastify[keys.kContentTypeParser].getParser('text/html; charset=utf-8').fn, third)
t.equal(fastify[keys.kContentTypeParser].getParser('text/html ; charset=utf-8').fn, third)
t.equal(fastify[keys.kContentTypeParser].getParser('text/htmlINVALID')?.fn, undefined)
})
test('should return matching parser with caching', t => {
test('should return matching parser with caching /1', t => {
t.plan(6)

@@ -82,2 +87,17 @@

test('should return matching parser with caching /2', t => {
t.plan(6)
const fastify = Fastify()
fastify.addContentTypeParser(/^text\/html(;\s*charset=[^;]+)?$/, first)
t.equal(fastify[keys.kContentTypeParser].getParser('text/html').fn, first)
t.equal(fastify[keys.kContentTypeParser].cache.size, 1)
t.equal(fastify[keys.kContentTypeParser].getParser('text/html;charset=utf-8').fn, first)
t.equal(fastify[keys.kContentTypeParser].cache.size, 2)
t.equal(fastify[keys.kContentTypeParser].getParser('text/html;charset=utf-8').fn, first)
t.equal(fastify[keys.kContentTypeParser].cache.size, 2)
})
test('should prefer content type parser with string value', t => {

@@ -209,2 +229,32 @@ t.plan(2)

test('should lowercase contentTypeParser name', async t => {
t.plan(1)
const fastify = Fastify()
fastify.addContentTypeParser('text/html', function (req, done) {
done()
})
try {
fastify.addContentTypeParser('TEXT/html', function (req, done) {
done()
})
} catch (err) {
t.same(err.message, FST_ERR_CTP_ALREADY_PRESENT('text/html').message)
}
})
test('should trim contentTypeParser name', async t => {
t.plan(1)
const fastify = Fastify()
fastify.addContentTypeParser('text/html', function (req, done) {
done()
})
try {
fastify.addContentTypeParser(' text/html', function (req, done) {
done()
})
} catch (err) {
t.same(err.message, FST_ERR_CTP_ALREADY_PRESENT('text/html').message)
}
})
t.end()

@@ -267,3 +317,3 @@ })

test('should remove default parser', t => {
t.plan(3)
t.plan(6)

@@ -276,2 +326,5 @@ const fastify = Fastify()

t.notOk(contentTypeParser.parserList.find(parser => parser === 'application/json'))
t.ok(contentTypeParser.remove(' text/plain '))
t.notOk(contentTypeParser.customParsers['text/plain'])
t.notOk(contentTypeParser.parserList.find(parser => parser === 'text/plain'))
})

@@ -434,28 +487,21 @@

test('Safeguard against content-type spoofing - regexp', async t => {
t.plan(1)
test('Warning against improper content-type - regexp', t => {
t.plan(2)
const fastify = Fastify()
process.on('warning', onWarning)
function onWarning (warning) {
t.equal(warning.name, 'FastifySecurity')
t.equal(warning.code, 'FSTSEC001')
}
t.teardown(() => process.removeListener('warning', onWarning))
fastify.removeAllContentTypeParsers()
fastify.addContentTypeParser(/text\/plain/, function (request, body, done) {
t.pass('should be called')
done(null, body)
})
fastify.addContentTypeParser(/application\/json/, function (request, body, done) {
t.fail('shouldn\'t be called')
done(null, body)
})
fastify.post('/', async () => {
return 'ok'
})
await fastify.inject({
method: 'POST',
path: '/',
headers: {
'content-type': 'text/plain; content-type="application/json"'
},
body: ''
})
})

@@ -491,30 +537,2 @@

test('content-type match parameters - string 2', async t => {
t.plan(1)
const fastify = Fastify()
fastify.removeAllContentTypeParsers()
fastify.addContentTypeParser('application/json; charset=utf8; foo=bar', function (request, body, done) {
t.pass('should be called')
done(null, body)
})
fastify.addContentTypeParser('text/plain; charset=utf8; foo=bar', function (request, body, done) {
t.fail('shouldn\'t be called')
done(null, body)
})
fastify.post('/', async () => {
return 'ok'
})
await fastify.inject({
method: 'POST',
path: '/',
headers: {
'content-type': 'application/json; foo=bar; charset=utf8'
},
body: ''
})
})
test('content-type match parameters - regexp', async t => {

@@ -665,68 +683,2 @@ t.plan(1)

test('allow partial content-type - essence check', async t => {
t.plan(1)
const fastify = Fastify()
fastify.removeAllContentTypeParsers()
fastify.addContentTypeParser('json', function (request, body, done) {
t.pass('should be called')
done(null, body)
})
fastify.post('/', async () => {
return 'ok'
})
await fastify.inject({
method: 'POST',
path: '/',
headers: {
'content-type': 'application/json; foo=bar; charset=utf8'
},
body: ''
})
await fastify.inject({
method: 'POST',
path: '/',
headers: {
'content-type': 'image/jpeg'
},
body: ''
})
})
test('allow partial content-type - not essence check', async t => {
t.plan(1)
const fastify = Fastify()
fastify.removeAllContentTypeParsers()
fastify.addContentTypeParser('json;', function (request, body, done) {
t.pass('should be called')
done(null, body)
})
fastify.post('/', async () => {
return 'ok'
})
await fastify.inject({
method: 'POST',
path: '/',
headers: {
'content-type': 'application/json; foo=bar; charset=utf8'
},
body: ''
})
await fastify.inject({
method: 'POST',
path: '/',
headers: {
'content-type': 'image/jpeg'
},
body: ''
})
})
test('edge case content-type - ;', async t => {

@@ -733,0 +685,0 @@ t.plan(1)

@@ -66,3 +66,3 @@ 'use strict'

test('Should get the body as string', t => {
test('Should get the body as string /1', t => {
t.plan(6)

@@ -106,2 +106,41 @@ const fastify = Fastify()

test('Should get the body as string /2', t => {
t.plan(6)
const fastify = Fastify()
fastify.post('/', (req, reply) => {
reply.send(req.body)
})
fastify.addContentTypeParser('text/plain/test', { parseAs: 'string' }, function (req, body, done) {
t.ok('called')
t.ok(typeof body === 'string')
try {
const plainText = body
done(null, plainText)
} catch (err) {
err.statusCode = 400
done(err, undefined)
}
})
fastify.listen({ port: 0 }, err => {
t.error(err)
sget({
method: 'POST',
url: getServerUrl(fastify),
body: 'hello world',
headers: {
'Content-Type': ' text/plain/test '
}
}, (err, response, body) => {
t.error(err)
t.equal(response.statusCode, 200)
t.equal(body.toString(), 'hello world')
fastify.close()
})
})
})
test('Should get the body as buffer', t => {

@@ -108,0 +147,0 @@ t.plan(6)

'use strict'
/* eslint no-prototype-builtins: 0 */
const t = require('tap')

@@ -11,3 +9,2 @@ const test = t.test

const symbols = require('../lib/symbols.js')
const proxyquire = require('proxyquire')

@@ -793,46 +790,41 @@ test('server methods should exist', t => {

test('decorate* should emit warning if an array is passed', t => {
t.plan(1)
test('decorate* should emit error if an array is passed', t => {
t.plan(2)
function onWarning (name) {
t.equal(name, 'test_array')
const fastify = Fastify()
try {
fastify.decorateRequest('test_array', [])
t.fail('should not decorate')
} catch (err) {
t.same(err.code, 'FST_ERR_DEC_REFERENCE_TYPE')
t.same(err.message, "The decorator 'test_array' of type 'object' is a reference type. Use the { getter, setter } interface instead.")
}
})
const decorate = proxyquire('../lib/decorate', {
'./warnings': {
FSTDEP006: onWarning
}
})
const fastify = proxyquire('..', { './lib/decorate.js': decorate })()
fastify.decorateRequest('test_array', [])
test('server.decorate should not emit error if reference type is passed', async t => {
t.plan(1)
const fastify = Fastify()
fastify.decorate('test_array', [])
fastify.decorate('test_object', {})
await fastify.ready()
t.pass('Done')
})
test('decorate* should emit warning if object type is passed', t => {
t.plan(1)
t.plan(2)
function onWarning (name) {
t.equal(name, 'test_object')
const fastify = Fastify()
try {
fastify.decorateRequest('test_object', { foo: 'bar' })
t.fail('should not decorate')
} catch (err) {
t.same(err.code, 'FST_ERR_DEC_REFERENCE_TYPE')
t.same(err.message, "The decorator 'test_object' of type 'object' is a reference type. Use the { getter, setter } interface instead.")
}
const decorate = proxyquire('../lib/decorate', {
'./warnings': {
FSTDEP006: onWarning
}
})
const fastify = proxyquire('..', { './lib/decorate.js': decorate })()
fastify.decorateRequest('test_object', { foo: 'bar' })
})
test('decorate* should not emit warning if object with getter/setter is passed', t => {
function onWarning (warning) {
t.fail('Should not call a warn')
}
const fastify = Fastify()
const decorate = proxyquire('../lib/decorate', {
'./warnings': {
FSTDEP006: onWarning
}
})
const fastify = proxyquire('..', { './lib/decorate.js': decorate })()
fastify.decorateRequest('test_getter_setter', {

@@ -849,14 +841,71 @@ setter (val) {

test('decorate* should not emit warning if string,bool,numbers are passed', t => {
function onWarning (warning) {
t.fail('Should not call a warn')
}
test('decorateRequest with getter/setter can handle encapsulation', async t => {
t.plan(24)
const decorate = proxyquire('../lib/decorate', {
'./warnings': {
FSTDEP006: onWarning
const fastify = Fastify({ logger: true })
fastify.decorateRequest('test_getter_setter_holder')
fastify.decorateRequest('test_getter_setter', {
getter () {
this.test_getter_setter_holder ??= {}
return this.test_getter_setter_holder
}
})
const fastify = proxyquire('..', { './lib/decorate.js': decorate })()
fastify.get('/', async function (req, reply) {
t.same(req.test_getter_setter, {}, 'a getter')
req.test_getter_setter.a = req.id
t.same(req.test_getter_setter, { a: req.id })
})
fastify.addHook('onResponse', async function hook (req, reply) {
t.same(req.test_getter_setter, { a: req.id })
})
await Promise.all([
fastify.inject('/').then(res => t.same(res.statusCode, 200)),
fastify.inject('/').then(res => t.same(res.statusCode, 200)),
fastify.inject('/').then(res => t.same(res.statusCode, 200)),
fastify.inject('/').then(res => t.same(res.statusCode, 200)),
fastify.inject('/').then(res => t.same(res.statusCode, 200)),
fastify.inject('/').then(res => t.same(res.statusCode, 200))
])
})
test('decorateRequest with getter/setter can handle encapsulation with arrays', async t => {
t.plan(24)
const fastify = Fastify({ logger: true })
fastify.decorateRequest('array_holder')
fastify.decorateRequest('my_array', {
getter () {
this.array_holder ??= []
return this.array_holder
}
})
fastify.get('/', async function (req, reply) {
t.same(req.my_array, [])
req.my_array.push(req.id)
t.same(req.my_array, [req.id])
})
fastify.addHook('onResponse', async function hook (req, reply) {
t.same(req.my_array, [req.id])
})
await Promise.all([
fastify.inject('/').then(res => t.same(res.statusCode, 200)),
fastify.inject('/').then(res => t.same(res.statusCode, 200)),
fastify.inject('/').then(res => t.same(res.statusCode, 200)),
fastify.inject('/').then(res => t.same(res.statusCode, 200)),
fastify.inject('/').then(res => t.same(res.statusCode, 200)),
fastify.inject('/').then(res => t.same(res.statusCode, 200))
])
})
test('decorate* should not emit error if string,bool,numbers are passed', t => {
const fastify = Fastify()
fastify.decorateRequest('test_str', 'foo')

@@ -863,0 +912,0 @@ fastify.decorateRequest('test_bool', true)

@@ -303,4 +303,24 @@ 'use strict'

test('shorthand - delete with application/json Content-Type header and null body', t => {
t.plan(4)
const fastify = require('..')()
fastify.delete('/', {}, (req, reply) => {
t.equal(req.body, null)
reply.send(req.body)
})
fastify.inject({
method: 'DELETE',
url: '/',
headers: { 'Content-Type': 'application/json' },
body: 'null'
}, (err, response) => {
t.error(err)
t.equal(response.statusCode, 200)
t.same(response.payload.toString(), 'null')
})
})
// https://github.com/fastify/fastify/issues/936
test('shorthand - delete with application/json Content-Type header and without body', t => {
// Skip this test because this is an invalid request
test('shorthand - delete with application/json Content-Type header and without body', { skip: 'https://github.com/fastify/fastify/pull/5419' }, t => {
t.plan(4)

@@ -307,0 +327,0 @@ const fastify = require('..')()

@@ -6,3 +6,6 @@ 'use strict'

test('encapsulates an error handler', async t => {
// Because of how error handlers wrap things, following the control flow can be tricky
// In this test file numbered comments indicate the order statements are expected to execute
test('encapsulates an asynchronous error handler', async t => {
t.plan(3)

@@ -13,17 +16,55 @@

fastify.setErrorHandler(async function a (err) {
t.equal(err.message, 'kaboom')
throw new Error('caught')
// 3. the inner error handler catches the error, and throws a new error
t.equal(err.message, 'from_endpoint')
throw new Error('from_inner')
})
fastify.get('/encapsulated', async () => { throw new Error('kaboom') })
fastify.get('/encapsulated', async () => {
// 2. the endpoint throws an error
throw new Error('from_endpoint')
})
})
fastify.setErrorHandler(async function b (err) {
t.equal(err.message, 'caught')
throw new Error('wrapped')
// 4. the outer error handler catches the error thrown by the inner error handler
t.equal(err.message, 'from_inner')
// 5. the outer error handler throws a new error
throw new Error('from_outer')
})
// 1. the endpoint is called
const res = await fastify.inject('/encapsulated')
t.equal(res.json().message, 'wrapped')
// 6. the default error handler returns the error from the outer error handler
t.equal(res.json().message, 'from_outer')
})
// See discussion in https://github.com/fastify/fastify/pull/5222#discussion_r1432573655
test('encapsulates a synchronous error handler', async t => {
t.plan(3)
const fastify = Fastify()
fastify.register(async function (fastify) {
fastify.setErrorHandler(function a (err) {
// 3. the inner error handler catches the error, and throws a new error
t.equal(err.message, 'from_endpoint')
throw new Error('from_inner')
})
fastify.get('/encapsulated', async () => {
// 2. the endpoint throws an error
throw new Error('from_endpoint')
})
})
fastify.setErrorHandler(async function b (err) {
// 4. the outer error handler catches the error thrown by the inner error handler
t.equal(err.message, 'from_inner')
// 5. the outer error handler throws a new error
throw new Error('from_outer')
})
// 1. the endpoint is called
const res = await fastify.inject('/encapsulated')
// 6. the default error handler returns the error from the outer error handler
t.equal(res.json().message, 'from_outer')
})
test('onError hook nested', async t => {

@@ -35,19 +76,165 @@ t.plan(4)

fastify.setErrorHandler(async function a (err) {
t.equal(err.message, 'kaboom')
throw new Error('caught')
// 4. the inner error handler catches the error, and throws a new error
t.equal(err.message, 'from_endpoint')
throw new Error('from_inner')
})
fastify.get('/encapsulated', async () => { throw new Error('kaboom') })
fastify.get('/encapsulated', async () => {
// 2. the endpoint throws an error
throw new Error('from_endpoint')
})
})
fastify.setErrorHandler(async function b (err) {
t.equal(err.message, 'caught')
throw new Error('wrapped')
// 5. the outer error handler catches the error thrown by the inner error handler
t.equal(err.message, 'from_inner')
// 6. the outer error handler throws a new error
throw new Error('from_outer')
})
fastify.addHook('onError', async function (request, reply, err) {
t.equal(err.message, 'kaboom')
// 3. the hook receives the error
t.equal(err.message, 'from_endpoint')
})
// 1. the endpoint is called
const res = await fastify.inject('/encapsulated')
t.equal(res.json().message, 'wrapped')
// 7. the default error handler returns the error from the outer error handler
t.equal(res.json().message, 'from_outer')
})
// See https://github.com/fastify/fastify/issues/5220
test('encapuslates an error handler, for errors thrown in hooks', async t => {
t.plan(3)
const fastify = Fastify()
fastify.register(async function (fastify) {
fastify.setErrorHandler(function a (err) {
// 3. the inner error handler catches the error, and throws a new error
t.equal(err.message, 'from_hook')
throw new Error('from_inner')
})
fastify.addHook('onRequest', async () => {
// 2. the hook throws an error
throw new Error('from_hook')
})
fastify.get('/encapsulated', async () => {})
})
fastify.setErrorHandler(function b (err) {
// 4. the outer error handler catches the error thrown by the inner error handler
t.equal(err.message, 'from_inner')
// 5. the outer error handler throws a new error
throw new Error('from_outer')
})
// 1. the endpoint is called
const res = await fastify.inject('/encapsulated')
// 6. the default error handler returns the error from the outer error handler
t.equal(res.json().message, 'from_outer')
})
// See https://github.com/fastify/fastify/issues/5220
test('encapuslates many synchronous error handlers that rethrow errors', async t => {
const DEPTH = 100
t.plan(DEPTH + 2)
/**
* This creates a very nested set of error handlers, that looks like:
* plugin
* - error handler
* - plugin
* - error handler
* - plugin
* ... {to DEPTH levels}
* - plugin
* - error handler
* - GET /encapsulated
*/
const createNestedRoutes = (fastify, depth) => {
if (depth < 0) {
throw new Error('Expected depth >= 0')
} else if (depth === 0) {
fastify.setErrorHandler(function a (err) {
// 3. innermost error handler catches the error, and throws a new error
t.equal(err.message, 'from_route')
throw new Error(`from_handler_${depth}`)
})
fastify.get('/encapsulated', async () => {
// 2. the endpoint throws an error
throw new Error('from_route')
})
} else {
fastify.setErrorHandler(function d (err) {
// 4 to {DEPTH+4}. error handlers each catch errors, and then throws a new error
t.equal(err.message, `from_handler_${depth - 1}`)
throw new Error(`from_handler_${depth}`)
})
fastify.register(async function (fastify) {
createNestedRoutes(fastify, depth - 1)
})
}
}
const fastify = Fastify()
createNestedRoutes(fastify, DEPTH)
// 1. the endpoint is called
const res = await fastify.inject('/encapsulated')
// {DEPTH+5}. the default error handler returns the error from the outermost error handler
t.equal(res.json().message, `from_handler_${DEPTH}`)
})
// See https://github.com/fastify/fastify/issues/5220
// This was not failing previously, but we want to make sure the behavior continues to work in the same way across async and sync handlers
// Plus, the current setup is somewhat fragile to tweaks to wrapThenable as that's what retries (by calling res.send(err) again)
test('encapuslates many asynchronous error handlers that rethrow errors', async t => {
const DEPTH = 100
t.plan(DEPTH + 2)
/**
* This creates a very nested set of error handlers, that looks like:
* plugin
* - error handler
* - plugin
* - error handler
* - plugin
* ... {to DEPTH levels}
* - plugin
* - error handler
* - GET /encapsulated
*/
const createNestedRoutes = (fastify, depth) => {
if (depth < 0) {
throw new Error('Expected depth >= 0')
} else if (depth === 0) {
fastify.setErrorHandler(async function a (err) {
// 3. innermost error handler catches the error, and throws a new error
t.equal(err.message, 'from_route')
throw new Error(`from_handler_${depth}`)
})
fastify.get('/encapsulated', async () => {
// 2. the endpoint throws an error
throw new Error('from_route')
})
} else {
fastify.setErrorHandler(async function m (err) {
// 4 to {DEPTH+4}. error handlers each catch errors, and then throws a new error
t.equal(err.message, `from_handler_${depth - 1}`)
throw new Error(`from_handler_${depth}`)
})
fastify.register(async function (fastify) {
createNestedRoutes(fastify, depth - 1)
})
}
}
const fastify = Fastify()
createNestedRoutes(fastify, DEPTH)
// 1. the endpoint is called
const res = await fastify.inject('/encapsulated')
// {DEPTH+5}. the default error handler returns the error from the outermost error handler
t.equal(res.json().message, `from_handler_${DEPTH}`)
})
'use strict'
const t = require('tap')
const semver = require('semver')
if (semver.lt(process.versions.node, '14.13.0')) {
t.skip('Skip named exports because Node version < 14.13.0')
} else {
// Node v8 throw a `SyntaxError: Unexpected token import`
// even if this branch is never touch in the code,
// by using `eval` we can avoid this issue.
// eslint-disable-next-line
new Function('module', 'return import(module)')('./named-exports.mjs').catch((err) => {
import('./named-exports.mjs')
.catch(err => {
process.nextTick(() => {

@@ -18,2 +9,1 @@ throw err

})
}

@@ -52,2 +52,18 @@ 'use strict'

test('findRoute should return null when when url is not passed', t => {
t.plan(1)
const fastify = Fastify()
fastify.get('/artists/:artistId', {
schema: {
params: { artistId: { type: 'integer' } }
},
handler: (req, reply) => reply.send(typeof req.params.artistId)
})
t.equal(fastify.findRoute({
method: 'POST'
}), null)
})
test('findRoute should return null when route cannot be found due to a different path', t => {

@@ -54,0 +70,0 @@ t.plan(1)

@@ -77,2 +77,11 @@ 'use strict'

test('Should handle properly requestIdHeader option', t => {
t.plan(4)
t.equal(Fastify({ requestIdHeader: '' }).initialConfig.requestIdHeader, false)
t.equal(Fastify({ requestIdHeader: false }).initialConfig.requestIdHeader, false)
t.equal(Fastify({ requestIdHeader: true }).initialConfig.requestIdHeader, 'request-id')
t.equal(Fastify({ requestIdHeader: 'x-request-id' }).initialConfig.requestIdHeader, 'x-request-id')
})
test('Should accept option to set genReqId with setGenReqId option', t => {

@@ -79,0 +88,0 @@ t.plan(9)

@@ -206,2 +206,14 @@ 'use strict'

test('shorthand - get, set port', t => {
t.plan(1)
try {
fastify.get('/port', headersSchema, function (req, reply) {
reply.code(200).send({ port: req.port })
})
t.pass()
} catch (e) {
t.fail()
}
})
fastify.listen({ port: 0 }, err => {

@@ -384,2 +396,18 @@ t.error(err)

})
test('shorthand - request get headers - test fall back port', t => {
t.plan(3)
sget({
method: 'GET',
headers: {
host: 'example.com'
},
json: true,
url: 'http://localhost:' + fastify.server.address().port + '/port'
}, (err, response, body) => {
t.error(err)
t.equal(response.statusCode, 200)
t.equal(body.port, null)
})
})
})

@@ -74,3 +74,3 @@ 'use strict'

method: 'GET',
url: '/example/12345.png'
url: '/example/:file(^\\d+).png'
}), true)

@@ -77,0 +77,0 @@ })

@@ -219,7 +219,3 @@ 'use strict'

t.error(err)
if (upMethod === 'OPTIONS') {
t.equal(response.statusCode, 200)
} else {
t.equal(response.statusCode, 415)
}
t.equal(response.statusCode, 415)
})

@@ -226,0 +222,0 @@ })

@@ -15,3 +15,3 @@ 'use strict'

test('A route supports host constraints under http2 protocol and secure connection', (t) => {
t.plan(5)
t.plan(6)

@@ -49,2 +49,10 @@ let fastify

})
fastify.route({
method: 'GET',
url: '/hostname_port',
constraints: { host: constrain },
handler: function (req, reply) {
reply.code(200).send({ ...beta, hostname: req.hostname })
}
})

@@ -92,3 +100,16 @@ fastify.listen({ port: 0 }, err => {

})
t.test('https get request - constrain - verify hostname and port from request', async (t) => {
t.plan(1)
const url = `https://localhost:${fastify.server.address().port}/hostname_port`
const res = await h2url.concat({
url,
headers: {
':authority': constrain
}
})
const body = JSON.parse(res.body)
t.equal(body.hostname, constrain)
})
})
})

@@ -23,6 +23,10 @@ 'use strict'

fastify.get('/hostname', function (req, reply) {
reply.code(200).send(req.hostname)
fastify.get('/host', function (req, reply) {
reply.code(200).send(req.host)
})
fastify.get('/hostname_port', function (req, reply) {
reply.code(200).send({ hostname: req.hostname, port: req.port })
})
fastify.listen({ port: 0 }, err => {

@@ -44,12 +48,23 @@ t.error(err)

test('http hostname', async (t) => {
test('http host', async (t) => {
t.plan(1)
const hostname = `localhost:${fastify.server.address().port}`
const host = `localhost:${fastify.server.address().port}`
const url = `http://${hostname}/hostname`
const url = `http://${host}/host`
const res = await h2url.concat({ url })
t.equal(res.body, hostname)
t.equal(res.body, host)
})
test('http hostname and port', async (t) => {
t.plan(2)
const host = `localhost:${fastify.server.address().port}`
const url = `http://${host}/hostname_port`
const res = await h2url.concat({ url })
t.equal(JSON.parse(res.body).hostname, host.split(':')[0])
t.equal(JSON.parse(res.body).port, parseInt(host.split(':')[1]))
})
})

@@ -13,3 +13,3 @@ 'use strict'

test('secure', (t) => {
t.plan(4)
t.plan(5)

@@ -36,2 +36,5 @@ let fastify

})
fastify.get('/hostname_port', function (req, reply) {
reply.code(200).send({ hostname: req.hostname, port: req.port })
})

@@ -60,3 +63,11 @@ fastify.listen({ port: 0 }, err => {

})
t.test('https get request - test hostname and port', async (t) => {
t.plan(2)
const url = `https://localhost:${fastify.server.address().port}/hostname_port`
const parsedbody = JSON.parse((await h2url.concat({ url })).body)
t.equal(parsedbody.hostname, 'localhost')
t.equal(parsedbody.port, fastify.server.address().port)
})
})
})

@@ -77,1 +77,58 @@ 'use strict'

})
test('https - headers', (t) => {
t.plan(4)
let fastify
try {
fastify = Fastify({
https: {
key: global.context.key,
cert: global.context.cert
}
})
t.pass('Key/cert successfully loaded')
} catch (e) {
t.fail('Key/cert loading failed', e)
}
fastify.get('/', function (req, reply) {
reply.code(200).send({ hello: 'world', hostname: req.hostname, port: req.port })
})
t.teardown(async () => { await fastify.close() })
fastify.listen({ port: 0 }, err => {
t.error(err)
t.test('https get request', t => {
t.plan(4)
sget({
method: 'GET',
url: 'https://localhost:' + fastify.server.address().port,
rejectUnauthorized: false
}, (err, response, body) => {
t.error(err)
t.equal(response.statusCode, 200)
const parsedBody = JSON.parse(body)
t.equal(parsedBody.hostname, 'localhost')
t.equal(parsedBody.port, fastify.server.address().port)
})
})
t.test('https get request - test port fall back', t => {
t.plan(3)
sget({
method: 'GET',
headers: {
host: 'example.com'
},
url: 'https://localhost:' + fastify.server.address().port,
rejectUnauthorized: false
}, (err, response, body) => {
t.error(err)
t.equal(response.statusCode, 200)
const parsedBody = JSON.parse(body)
t.equal(parsedBody.port, null)
})
})
})
})

@@ -8,3 +8,2 @@ 'use strict'

const Fastify = require('..')
const FormData = require('form-data')
const { Readable } = require('node:stream')

@@ -347,3 +346,3 @@

const form = new FormData()
form.append('my_field', 'my value')
form.set('my_field', 'my value')

@@ -350,0 +349,0 @@ fastify.inject({

'use strict'
/* eslint no-prototype-builtins: 0 */
const t = require('tap')

@@ -6,0 +4,0 @@ const test = t.test

@@ -8,3 +8,3 @@ 'use strict'

test('should expose 80 errors', t => {
test('should expose 84 errors', t => {
t.plan(1)

@@ -18,7 +18,7 @@ const exportedKeys = Object.keys(errors)

}
t.equal(counter, 80)
t.equal(counter, 84)
})
test('ensure name and codes of Errors are identical', t => {
t.plan(80)
t.plan(84)
const exportedKeys = Object.keys(errors)

@@ -252,2 +252,12 @@ for (const key of exportedKeys) {

test('FST_ERR_DEC_REFERENCE_TYPE', t => {
t.plan(5)
const error = new errors.FST_ERR_DEC_REFERENCE_TYPE()
t.equal(error.name, 'FastifyError')
t.equal(error.code, 'FST_ERR_DEC_REFERENCE_TYPE')
t.equal(error.message, "The decorator '%s' of type '%s' is a reference type. Use the { getter, setter } interface instead.")
t.equal(error.statusCode, 500)
t.ok(error instanceof Error)
})
test('FST_ERR_HOOK_INVALID_TYPE', t => {

@@ -333,2 +343,32 @@ t.plan(5)

test('FST_ERR_LOG_INVALID_LOGGER_INSTANCE', t => {
t.plan(5)
const error = new errors.FST_ERR_LOG_INVALID_LOGGER_INSTANCE()
t.equal(error.name, 'FastifyError')
t.equal(error.code, 'FST_ERR_LOG_INVALID_LOGGER_INSTANCE')
t.equal(error.message, 'loggerInstance only accepts a logger instance.')
t.equal(error.statusCode, 500)
t.ok(error instanceof TypeError)
})
test('FST_ERR_LOG_INVALID_LOGGER_CONFIG', t => {
t.plan(5)
const error = new errors.FST_ERR_LOG_INVALID_LOGGER_CONFIG()
t.equal(error.name, 'FastifyError')
t.equal(error.code, 'FST_ERR_LOG_INVALID_LOGGER_CONFIG')
t.equal(error.message, 'logger options only accepts a configuration object.')
t.equal(error.statusCode, 500)
t.ok(error instanceof TypeError)
})
test('FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED', t => {
t.plan(5)
const error = new errors.FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED()
t.equal(error.name, 'FastifyError')
t.equal(error.code, 'FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED')
t.equal(error.message, 'You cannot provide both logger and loggerInstance. Please provide only one.')
t.equal(error.statusCode, 500)
t.ok(error instanceof TypeError)
})
test('FST_ERR_REP_INVALID_PAYLOAD_TYPE', t => {

@@ -594,12 +634,2 @@ t.plan(5)

test('FST_ERR_DEFAULT_ROUTE_INVALID_TYPE', t => {
t.plan(5)
const error = new errors.FST_ERR_DEFAULT_ROUTE_INVALID_TYPE()
t.equal(error.name, 'FastifyError')
t.equal(error.code, 'FST_ERR_DEFAULT_ROUTE_INVALID_TYPE')
t.equal(error.message, 'The defaultRoute type should be a function')
t.equal(error.statusCode, 500)
t.ok(error instanceof TypeError)
})
test('FST_ERR_INVALID_URL', t => {

@@ -765,2 +795,12 @@ t.plan(5)

test('FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER', t => {
t.plan(5)
const error = new errors.FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER('easter-egg')
t.equal(error.name, 'FastifyError')
t.equal(error.code, 'FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER')
t.equal(error.message, 'The easter-egg plugin being registered mixes async and callback styles. Async plugin should not mix async and callback style.')
t.equal(error.statusCode, 500)
t.ok(error instanceof TypeError)
})
test('FST_ERR_PLUGIN_CALLBACK_NOT_FN', t => {

@@ -847,3 +887,3 @@ t.plan(5)

test('Ensure that all errors are in Errors.md TOC', t => {
t.plan(80)
t.plan(84)
const errorsMd = readFileSync(resolve(__dirname, '../../docs/Reference/Errors.md'), 'utf8')

@@ -860,3 +900,3 @@

test('Ensure that non-existing errors are not in Errors.md TOC', t => {
t.plan(80)
t.plan(84)
const errorsMd = readFileSync(resolve(__dirname, '../../docs/Reference/Errors.md'), 'utf8')

@@ -874,3 +914,3 @@

test('Ensure that all errors are in Errors.md documented', t => {
t.plan(80)
t.plan(84)
const errorsMd = readFileSync(resolve(__dirname, '../../docs/Reference/Errors.md'), 'utf8')

@@ -887,3 +927,3 @@

test('Ensure that non-existing errors are not in Errors.md documented', t => {
t.plan(80)
t.plan(84)
const errorsMd = readFileSync(resolve(__dirname, '../../docs/Reference/Errors.md'), 'utf8')

@@ -890,0 +930,0 @@

@@ -97,3 +97,7 @@ 'use strict'

onSend: [],
onError: []
onError: [],
config: {
url: '',
method: ''
}
}

@@ -100,0 +104,0 @@ buildSchema(context, schemaValidator)

@@ -48,7 +48,7 @@ 'use strict'

pluginTimeout: 10000,
requestIdHeader: 'request-id',
requestIdHeader: false,
requestIdLogLabel: 'reqId',
http2SessionTimeout: 72000,
exposeHeadRoutes: true,
useSemicolonDelimiter: true
useSemicolonDelimiter: false
}

@@ -109,3 +109,3 @@

},
logger: pino({ level: 'info' }),
loggerInstance: pino({ level: 'info' }),
constraints: {

@@ -290,7 +290,7 @@ version: versionStrategy

pluginTimeout: 10000,
requestIdHeader: 'request-id',
requestIdHeader: false,
requestIdLogLabel: 'reqId',
http2SessionTimeout: 72000,
exposeHeadRoutes: true,
useSemicolonDelimiter: true
useSemicolonDelimiter: false
})

@@ -297,0 +297,0 @@ } catch (error) {

@@ -49,3 +49,3 @@ 'use strict'

test('The logger should reuse request id header for req.id', t => {
test('The logger should not reuse request id header for req.id', t => {
const fastify = Fastify()

@@ -69,2 +69,31 @@ fastify.get('/', (req, reply) => {

const payload = JSON.parse(res.payload)
t.ok(payload.id !== 'request-id-1', 'the request id from the header should not be returned with default configuration')
t.ok(payload.id === 'req-1') // first request id when using the default configuration
fastify.close()
t.end()
})
})
})
test('The logger should reuse request id header for req.id if requestIdHeader is set', t => {
const fastify = Fastify({
requestIdHeader: 'request-id'
})
fastify.get('/', (req, reply) => {
t.ok(req.id)
reply.send({ id: req.id })
})
fastify.listen({ port: 0 }, err => {
t.error(err)
fastify.inject({
method: 'GET',
url: 'http://localhost:' + fastify.server.address().port,
headers: {
'Request-Id': 'request-id-1'
}
}, (err, res) => {
t.error(err)
const payload = JSON.parse(res.payload)
t.ok(payload.id === 'request-id-1', 'the request id from the header should be returned')

@@ -132,3 +161,3 @@ fastify.close()

version: undefined,
hostname: undefined,
host: undefined,
remoteAddress: undefined,

@@ -135,0 +164,0 @@ remotePort: undefined

@@ -22,3 +22,3 @@ 'use strict'

const path = require('node:path')
const { FSTDEP010, FSTDEP019, FSTDEP020, FSTDEP021 } = require('../../lib/warnings')
const { FSTDEP010, FSTDEP019, FSTDEP021 } = require('../../lib/warnings')

@@ -40,3 +40,3 @@ const agent = new http.Agent({ keepAlive: false })

test('Once called, Reply should return an object with methods', t => {
t.plan(16)
t.plan(15)
const response = { res: 'res' }

@@ -54,3 +54,2 @@ const context = { config: { onSend: [] }, schema: {} }

t.equal(typeof reply.serialize, 'function')
t.equal(typeof reply.getResponseTime, 'function')
t.equal(typeof reply[kReplyHeaders], 'object')

@@ -1421,5 +1420,5 @@ t.same(reply.raw, response)

fastify.get('/', function (req, reply) {
t.ok(reply.statusCode, 200, 'default status value')
t.equal(reply.statusCode, 200, 'default status value')
reply.statusCode = 418
t.ok(reply.statusCode, 418)
t.equal(reply.statusCode, 418)
reply.send()

@@ -1579,80 +1578,9 @@ })

test('reply.getResponseTime() should return 0 before the timer is initialised on the reply by setting up response listeners', t => {
test('reply.elapsedTime should return 0 before the timer is initialised on the reply by setting up response listeners', t => {
t.plan(1)
const response = { statusCode: 200 }
const reply = new Reply(response, null)
t.equal(reply.getResponseTime(), 0)
t.equal(reply.elapsedTime, 0)
})
test('reply.getResponseTime() should return a number greater than 0 after the timer is initialised on the reply by setting up response listeners', t => {
t.plan(1)
const fastify = Fastify()
fastify.route({
method: 'GET',
url: '/',
handler: (req, reply) => {
reply.send('hello world')
}
})
fastify.addHook('onResponse', (req, reply) => {
t.ok(reply.getResponseTime() > 0)
t.end()
})
fastify.inject({ method: 'GET', url: '/' })
})
test('should emit deprecation warning when trying to use reply.getResponseTime() and should return the time since a request started while inflight', t => {
t.plan(5)
const fastify = Fastify()
fastify.route({
method: 'GET',
url: '/',
handler: (req, reply) => {
reply.send('hello world')
}
})
process.removeAllListeners('warning')
process.on('warning', onWarning)
function onWarning (warning) {
t.equal(warning.name, 'DeprecationWarning')
t.equal(warning.code, FSTDEP020.code)
}
fastify.addHook('preValidation', (req, reply, done) => {
t.equal(reply.getResponseTime(), reply.getResponseTime())
done()
})
fastify.inject({ method: 'GET', url: '/' }, (err, res) => {
t.error(err)
t.pass()
process.removeListener('warning', onWarning)
})
FSTDEP020.emitted = false
})
test('reply.getResponseTime() should return the same value after a request is finished', t => {
t.plan(1)
const fastify = Fastify()
fastify.route({
method: 'GET',
url: '/',
handler: (req, reply) => {
reply.send('hello world')
}
})
fastify.addHook('onResponse', (req, reply) => {
t.equal(reply.getResponseTime(), reply.getResponseTime())
t.end()
})
fastify.inject({ method: 'GET', url: '/' })
})
test('reply.elapsedTime should return a number greater than 0 after the timer is initialised on the reply by setting up response listeners', t => {

@@ -1659,0 +1587,0 @@ t.plan(1)

@@ -63,3 +63,3 @@ 'use strict'

t.equal(request.ips, undefined)
t.equal(request.hostname, 'hostname')
t.equal(request.host, 'hostname')
t.equal(request.body, undefined)

@@ -146,3 +146,3 @@ t.equal(request.method, 'GET')

test('Regular request - hostname from authority', t => {
t.plan(2)
t.plan(3)
const headers = {

@@ -160,7 +160,8 @@ ':authority': 'authority'

t.type(request, Request)
t.equal(request.hostname, 'authority')
t.equal(request.host, 'authority')
t.equal(request.port, null)
})
test('Regular request - host header has precedence over authority', t => {
t.plan(2)
t.plan(3)
const headers = {

@@ -178,3 +179,4 @@ host: 'hostname',

t.type(request, Request)
t.equal(request.hostname, 'hostname')
t.equal(request.host, 'hostname')
t.equal(request.port, null)
})

@@ -229,3 +231,3 @@

t.same(request.ips, ['ip', '1.1.1.1', '2.2.2.2'])
t.equal(request.hostname, 'example.com')
t.equal(request.host, 'example.com')
t.equal(request.body, undefined)

@@ -280,3 +282,3 @@ t.equal(request.method, 'GET')

t.type(request, TpRequest)
t.equal(request.hostname, 'hostname')
t.equal(request.host, 'hostname')
})

@@ -300,3 +302,3 @@

t.type(request, TpRequest)
t.equal(request.hostname, 'authority')
t.equal(request.host, 'authority')
})

@@ -321,3 +323,3 @@

t.type(request, TpRequest)
t.equal(request.hostname, 'example.com')
t.equal(request.host, 'example.com')
})

@@ -341,3 +343,3 @@

t.type(request, TpRequest)
t.equal(request.hostname, 'example.com')
t.equal(request.host, 'example.com')
t.equal(request.protocol, 'https')

@@ -385,3 +387,3 @@ })

t.equal(request.ips, undefined)
t.equal(request.hostname, 'hostname')
t.equal(request.host, 'hostname')
t.same(request.body, null)

@@ -388,0 +390,0 @@ t.equal(request.method, 'GET')

@@ -32,3 +32,2 @@ 'use strict'

t.plan(1)
const fastify = Fastify()

@@ -38,17 +37,8 @@ t.teardown(fastify.close.bind(fastify))

const address = fastify.server.address()
t.equal(addr, `http://${address.address}:${address.port}`)
})
test('Promise listen with arguments', t => {
process.on('warning', () => {
t.fail('should not be deprecated')
t.equal(addr, `http://127.0.0.1:${address.port}`)
t.same(address, {
address: '0.0.0.0',
family: 'IPv4',
port: address.port
})
t.plan(1)
const fastify = Fastify()
t.teardown(fastify.close.bind(fastify))
fastify.listen({ port: 0, host: '0.0.0.0' }).then(addr => {
const address = fastify.server.address()
t.equal(addr, `http://${address.address}:${address.port}`)
})
})

@@ -55,0 +45,0 @@

@@ -35,5 +35,5 @@ 'use strict'

const logger = require('pino')(stream)
const loggerInstance = require('pino')(stream)
const fastify = Fastify({ logger })
const fastify = Fastify({ loggerInstance })
t.teardown(fastify.close.bind(fastify))

@@ -207,3 +207,3 @@

const logger = {
const loggerInstance = {
fatal: (msg) => { t.equal(msg, 'fatal') },

@@ -215,6 +215,6 @@ error: (msg) => { t.equal(msg, 'error') },

trace: (msg) => { t.equal(msg, 'trace') },
child: () => logger
child: () => loggerInstance
}
const fastify = Fastify({ logger })
const fastify = Fastify({ loggerInstance })
t.teardown(fastify.close.bind(fastify))

@@ -229,3 +229,3 @@

const child = fastify.log.child()
t.equal(child, logger)
t.equal(child, loggerInstance)
})

@@ -253,3 +253,3 @@

const stream = split(JSON.parse)
const logger = require('pino')({
const loggerInstance = require('pino')({
level: 'info',

@@ -266,3 +266,3 @@ serializers: {

const fastify = Fastify({
logger
loggerInstance
})

@@ -269,0 +269,0 @@ t.teardown(fastify.close.bind(fastify))

@@ -32,6 +32,6 @@ 'use strict'

const logger = pino({ level: 'trace' }, stream)
const loggerInstance = pino({ level: 'trace' }, stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -233,6 +233,6 @@ t.teardown(fastify.close.bind(fastify))

const stream = split(JSON.parse)
const logger = pino(stream)
const loggerInstance = pino(stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -239,0 +239,0 @@ t.teardown(fastify.close.bind(fastify))

@@ -15,3 +15,3 @@ 'use strict'

t.plan(12)
t.plan(16)

@@ -52,6 +52,6 @@ t.test('logger can be silenced', (t) => {

const logger = pino({ level: 'error' }, stream)
const loggerInstance = pino({ level: 'error' }, stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -99,6 +99,6 @@ t.teardown(fastify.close.bind(fastify))

const logger = pino({ level: 'error' }, stream)
const loggerInstance = pino({ level: 'error' }, stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -136,6 +136,6 @@ t.teardown(fastify.close.bind(fastify))

const logger = pino({ level: 'error' }, stream)
const loggerInstance = pino({ level: 'error' }, stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -200,5 +200,5 @@ t.teardown(fastify.close.bind(fastify))

const logger = pino({ level: 'info' }, stream)
const loggerInstance = pino({ level: 'info' }, stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -260,5 +260,5 @@ t.teardown(fastify.close.bind(fastify))

const logger = pino({ level: 'info' }, stream)
const loggerInstance = pino({ level: 'info' }, stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -299,5 +299,5 @@ t.teardown(fastify.close.bind(fastify))

const logger = pino({ level: 'info' }, stream)
const loggerInstance = pino({ level: 'info' }, stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -343,6 +343,6 @@ t.teardown(fastify.close.bind(fastify))

const logger = pino({ level: 'info' }, stream)
const loggerInstance = pino({ level: 'info' }, stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -380,6 +380,6 @@ t.teardown(fastify.close.bind(fastify))

const logger = pino({ level: 'warn' }, stream)
const loggerInstance = pino({ level: 'warn' }, stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -416,6 +416,6 @@ t.teardown(fastify.close.bind(fastify))

const logger = pino({ level: 'warn' }, stream)
const loggerInstance = pino({ level: 'warn' }, stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -457,6 +457,6 @@ t.teardown(fastify.close.bind(fastify))

const logger = pino({ level: 'error' }, stream)
const loggerInstance = pino({ level: 'error' }, stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -511,2 +511,83 @@ t.teardown(fastify.close.bind(fastify))

})
t.test('Should throw an error if logger instance is passed to `logger`', async (t) => {
t.plan(2)
const stream = split(JSON.parse)
const logger = require('pino')(stream)
try {
Fastify({ logger })
} catch (err) {
t.ok(err)
t.equal(err.code, 'FST_ERR_LOG_INVALID_LOGGER_CONFIG')
}
})
t.test('Should throw an error if options are passed to `loggerInstance`', async (t) => {
t.plan(2)
try {
Fastify({ loggerInstance: { level: 'log' } })
} catch (err) {
t.ok(err)
t.equal(err.code, 'FST_ERR_LOG_INVALID_LOGGER_INSTANCE')
}
})
t.test('If both `loggerInstance` and `logger` are provided, an error should be thrown', async (t) => {
t.plan(2)
const loggerInstanceStream = split(JSON.parse)
const loggerInstance = pino({ level: 'error' }, loggerInstanceStream)
const loggerStream = split(JSON.parse)
try {
Fastify({
logger: {
stream: loggerStream,
level: 'info'
},
loggerInstance
})
} catch (err) {
t.ok(err)
t.equal(err.code, 'FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED')
}
})
t.test('`logger` should take pino configuration and create a pino logger', async (t) => {
const lines = ['hello', 'world']
t.plan(2 * lines.length + 2)
const loggerStream = split(JSON.parse)
const fastify = Fastify({
logger: {
stream: loggerStream,
level: 'error'
}
})
t.teardown(fastify.close.bind(fastify))
fastify.get('/hello', (req, reply) => {
req.log.error('hello')
reply.code(404).send()
})
fastify.get('/world', (req, reply) => {
req.log.error('world')
reply.code(201).send()
})
await fastify.ready()
{
const response = await fastify.inject({ method: 'GET', url: '/hello' })
t.equal(response.statusCode, 404)
}
{
const response = await fastify.inject({ method: 'GET', url: '/world' })
t.equal(response.statusCode, 201)
}
for await (const [line] of on(loggerStream, 'data')) {
t.equal(line.level, 50)
t.equal(line.msg, lines.shift())
if (lines.length === 0) break
}
})
})

@@ -27,5 +27,5 @@ 'use strict'

const logger = pino({ level: 'info' }, stream)
const loggerInstance = pino({ level: 'info' }, stream)
const fastify = Fastify({
logger
loggerInstance
})

@@ -74,3 +74,3 @@ t.teardown(fastify.close.bind(fastify))

const logger = pino({
const loggerInstance = pino({
level: 'info',

@@ -83,3 +83,3 @@ serializers: {

const fastify = Fastify({
logger
loggerInstance
})

@@ -121,3 +121,3 @@ t.teardown(fastify.close.bind(fastify))

const logger = pino({
const loggerInstance = pino({
level: 'info',

@@ -129,3 +129,3 @@ serializers: {

const fastify = Fastify({ logger })
const fastify = Fastify({ loggerInstance })
t.teardown(fastify.close.bind(fastify))

@@ -132,0 +132,0 @@

@@ -5,8 +5,5 @@ 'use strict'

const { test } = require('tap')
const semver = require('semver')
const Fastify = require('../fastify')
const skip = semver.lt(process.versions.node, '16.10.0')
test('maxRequestsPerSocket on node version >= 16.10.0', { skip }, t => {
test('maxRequestsPerSocket', t => {
t.plan(8)

@@ -52,3 +49,3 @@

test('maxRequestsPerSocket zero should behave same as null', { skip }, t => {
test('maxRequestsPerSocket zero should behave same as null', t => {
t.plan(10)

@@ -55,0 +52,0 @@

'use strict'
/* eslint no-prototype-builtins: 0 */
const t = require('tap')

@@ -120,4 +118,4 @@ const test = t.test

t.notOk(p === instance || p === fastify)
t.ok(instance.isPrototypeOf(p))
t.ok(fastify.isPrototypeOf(p))
t.ok(Object.prototype.isPrototypeOf.call(instance, p))
t.ok(Object.prototype.isPrototypeOf.call(fastify, p))
t.ok(p.global)

@@ -124,0 +122,0 @@ })

'use strict'
/* eslint no-prototype-builtins: 0 */
const t = require('tap')

@@ -6,0 +4,0 @@ const test = t.test

'use strict'
/* eslint no-prototype-builtins: 0 */
const t = require('tap')

@@ -6,0 +4,0 @@ const test = t.test

'use strict'
/* eslint no-prototype-builtins: 0 */
const t = require('tap')

@@ -10,2 +8,3 @@ const test = t.test

const fakeTimer = require('@sinonjs/fake-timers')
const { FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER } = require('../lib/errors')

@@ -137,2 +136,5 @@ test('pluginTimeout', t => {

const fastify = Fastify()
Object.defineProperty(fastify, 'version', {
value: '99.0.0'
})

@@ -203,32 +205,71 @@ plugin[Symbol.for('skip-override')] = true

test('fastify-rc loads prior version plugins', t => {
t.plan(2)
const fastify = Fastify()
Object.defineProperty(fastify, 'version', {
value: '99.0.0-rc.1'
test('fastify-rc loads prior version plugins', async t => {
t.test('baseline (rc)', t => {
t.plan(2)
const fastify = Fastify()
Object.defineProperty(fastify, 'version', {
value: '99.0.0-rc.1'
})
plugin[Symbol.for('plugin-meta')] = {
name: 'plugin',
fastify: '^98.1.0'
}
plugin2[Symbol.for('plugin-meta')] = {
name: 'plugin2',
fastify: '98.x'
}
fastify.register(plugin)
fastify.ready((err) => {
t.error(err)
t.pass('everything right')
})
function plugin (instance, opts, done) {
done()
}
function plugin2 (instance, opts, done) {
done()
}
})
plugin[Symbol.for('plugin-meta')] = {
name: 'plugin',
fastify: '^98.1.0'
}
plugin2[Symbol.for('plugin-meta')] = {
name: 'plugin2',
fastify: '98.x'
}
t.test('pre', t => {
t.plan(2)
fastify.register(plugin)
const fastify = Fastify()
Object.defineProperty(fastify, 'version', { value: '99.0.0-pre.1' })
fastify.ready((err) => {
t.error(err)
t.pass('everything right')
plugin[Symbol.for('plugin-meta')] = { name: 'plugin', fastify: '^98.x' }
fastify.register(plugin)
fastify.ready((err) => {
t.error(err)
t.pass()
})
function plugin (instance, opts, done) { done() }
})
function plugin (instance, opts, done) {
done()
}
t.test('alpha', t => {
t.plan(2)
function plugin2 (instance, opts, done) {
done()
}
const fastify = Fastify()
Object.defineProperty(fastify, 'version', { value: '99.0.0-pre.1' })
plugin[Symbol.for('plugin-meta')] = { name: 'plugin', fastify: '^98.x' }
fastify.register(plugin)
fastify.ready((err) => {
t.error(err)
t.pass()
})
function plugin (instance, opts, done) { done() }
})
})

@@ -421,22 +462,25 @@

test('registering plugins with mixed style should return a warning', async t => {
t.plan(12)
test('registering anonymous plugin with mixed style should throw', async t => {
t.plan(2)
const pluginNames = ['error-plugin', 'anonymous', 'anotherPlugin', 'anotherPluginNamed']
const fastify = Fastify()
const oldWarnings = process.listeners('warning')
process.removeAllListeners('warning')
process.on('warning', onWarning)
function onWarning (warning) {
t.match(warning.message, new RegExp(`.*${pluginNames.shift()} plugin being registered mixes async and callback styles.*`))
t.equal(warning.name, 'FastifyWarning')
t.equal(warning.code, 'FSTWRN002')
const anonymousPlugin = async (app, opts, done) => {
done()
}
t.teardown(() => {
process.removeListener('warning', onWarning)
for (const warning of oldWarnings) {
process.on('warning', warning)
}
})
fastify.register(anonymousPlugin)
try {
await fastify.ready()
t.fail('should throw')
} catch (error) {
t.type(error, FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER)
t.equal(error.message, 'The anonymousPlugin plugin being registered mixes async and callback styles. Async plugin should not mix async and callback style.')
}
})
test('registering named plugin with mixed style should throw', async t => {
t.plan(2)
const fastify = Fastify()

@@ -448,21 +492,13 @@

}
const namedPlugin = fp(errorPlugin, { name: pluginName })
async function anotherPlugin (app, opts, done) {
done()
}
fastify.register(namedPlugin)
const anotherPluginNamed = async function (app, opts, done) {
done()
try {
await fastify.ready()
t.fail('should throw')
} catch (error) {
t.type(error, FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER)
t.equal(error.message, 'The error-plugin plugin being registered mixes async and callback styles. Async plugin should not mix async and callback style.')
}
fastify.register(namedPlugin)
fastify.register(async (app, opts, done) => {
done()
})
fastify.register(anotherPlugin)
fastify.register(anotherPluginNamed)
await fastify.ready()
})
'use strict'
/* eslint no-prototype-builtins: 0 */
const t = require('tap')

@@ -17,3 +15,3 @@ const test = t.test

t.not(instance, fastify)
t.ok(fastify.isPrototypeOf(instance))
t.ok(Object.prototype.isPrototypeOf.call(fastify, instance))

@@ -31,3 +29,3 @@ t.equal(typeof opts, 'object')

t.not(instance, fastify)
t.ok(fastify.isPrototypeOf(instance))
t.ok(Object.prototype.isPrototypeOf.call(fastify, instance))

@@ -34,0 +32,0 @@ t.equal(typeof opts, 'object')

@@ -606,3 +606,2 @@ 'use strict'

fastify.get('/', function (req, reply) {
// eslint-disable-next-line no-throw-literal
throw throwable

@@ -670,3 +669,2 @@ })

fastify.get('/', function async (req, reply) {
// eslint-disable-next-line no-throw-literal
throw throwable

@@ -673,0 +671,0 @@ })

@@ -258,3 +258,2 @@ 'use strict'

[hook]: async () => {
// eslint-disable-next-line no-throw-literal
throw myError

@@ -261,0 +260,0 @@ }

@@ -707,3 +707,3 @@ 'use strict'

test('The default schema compilers should not be called when overwritten by the user', async t => {
const Fastify = t.mock('../', {
const Fastify = t.mockRequire('../', {
'@fastify/ajv-compiler': () => {

@@ -710,0 +710,0 @@ t.fail('The default validator compiler should not be called')

@@ -6,3 +6,3 @@ 'use strict'

const Fastify = require('..')
const semver = require('semver')
const sget = require('simple-get').concat
const undici = require('undici')

@@ -76,3 +76,18 @@

test('abort signal', { skip: semver.lt(process.version, '16.0.0') }, t => {
test('Test for hostname and port', t => {
const app = Fastify()
t.teardown(app.close.bind(app))
app.get('/host', (req, res) => {
const host = 'localhost:8000'
t.equal(req.host, host)
t.equal(req.hostname, req.host.split(':')[0])
t.equal(req.port, Number(req.host.split(':')[1]))
res.send('ok')
})
app.listen({ port: 8000 }, () => {
sget('http://localhost:8000/host', () => { t.end() })
})
})
test('abort signal', t => {
t.test('listen should not start server', t => {

@@ -79,0 +94,0 @@ t.plan(2)

@@ -71,3 +71,3 @@ 'use strict'

const fastify = Fastify({ logger: spyLogger })
const fastify = Fastify({ loggerInstance: spyLogger })
fastify.get('/', function (req, reply) {

@@ -74,0 +74,0 @@ reply.send({ hello: 'world' })

@@ -6,12 +6,8 @@ 'use strict'

const sget = require('simple-get').concat
const fs = require('node:fs')
const errors = require('http-errors')
const JSONStream = require('JSONStream')
const send = require('send')
const Readable = require('node:stream').Readable
const split = require('split2')
const semver = require('semver')
const Fastify = require('..')
const { kDisableRequestLogging } = require('../lib/symbols.js')
const { getServerUrl } = require('./helper')

@@ -187,39 +183,1 @@ test('Destroying streams prematurely should call abort method', t => {

})
test('should support send module 200 and 404', { skip: semver.gte(process.versions.node, '17.0.0') }, t => {
t.plan(8)
const fastify = Fastify()
fastify.get('/', function (req, reply) {
const stream = send(req.raw, __filename)
reply.code(200).send(stream)
})
fastify.get('/error', function (req, reply) {
const stream = send(req.raw, 'non-existing-file')
reply.code(200).send(stream)
})
fastify.listen({ port: 0 }, err => {
t.error(err)
t.teardown(() => { fastify.close() })
const url = getServerUrl(fastify)
sget(url, function (err, response, data) {
t.error(err)
t.equal(response.headers['content-type'], 'application/javascript; charset=UTF-8')
t.equal(response.statusCode, 200)
fs.readFile(__filename, (err, expected) => {
t.error(err)
t.equal(expected.toString(), data.toString())
})
})
sget(url + '/error', function (err, response) {
t.error(err)
t.equal(response.statusCode, 404)
})
})
})

@@ -91,3 +91,3 @@ 'use strict'

const fastify = Fastify({
logger: spyLogger
loggerInstance: spyLogger
})

@@ -140,3 +140,3 @@

const fastify = Fastify({
logger: spyLogger
loggerInstance: spyLogger
})

@@ -143,0 +143,0 @@

@@ -29,5 +29,7 @@ 'use strict'

}
if (options.hostname) {
t.ok(req.hostname, 'hostname is defined')
t.equal(req.hostname, options.hostname, 'gets hostname from x-forwarded-host')
if (options.host) {
t.ok(req.host, 'host is defined')
t.equal(req.host, options.host, 'gets host from x-forwarded-host')
t.ok(req.hostname)
t.equal(req.hostname, options.host, 'gets hostname from x-forwarded-host')
}

@@ -41,2 +43,6 @@ if (options.ips) {

}
if (options.port) {
t.ok(req.port, 'port is defined')
t.equal(req.port, options.port, 'port is taken from x-forwarded-for or host')
}
}

@@ -50,3 +56,3 @@

test('trust proxy, not add properties to node req', (t) => {
t.plan(8)
t.plan(14)
const app = fastify({

@@ -56,9 +62,9 @@ trustProxy: true

app.get('/trustproxy', function (req, reply) {
testRequestValues(t, req, { ip: '1.1.1.1', hostname: 'example.com' })
reply.code(200).send({ ip: req.ip, hostname: req.hostname })
testRequestValues(t, req, { ip: '1.1.1.1', host: 'example.com', port: app.server.address().port })
reply.code(200).send({ ip: req.ip, host: req.host })
})
app.get('/trustproxychain', function (req, reply) {
testRequestValues(t, req, { ip: '2.2.2.2', ips: [localhost, '1.1.1.1', '2.2.2.2'] })
reply.code(200).send({ ip: req.ip, hostname: req.hostname })
testRequestValues(t, req, { ip: '2.2.2.2', ips: [localhost, '1.1.1.1', '2.2.2.2'], port: app.server.address().port })
reply.code(200).send({ ip: req.ip, host: req.host })
})

@@ -77,3 +83,3 @@

test('trust proxy chain', (t) => {
t.plan(3)
t.plan(9)
const app = fastify({

@@ -84,4 +90,4 @@ trustProxy: [localhost, '192.168.1.1']

app.get('/trustproxychain', function (req, reply) {
testRequestValues(t, req, { ip: '1.1.1.1' })
reply.code(200).send({ ip: req.ip, hostname: req.hostname })
testRequestValues(t, req, { ip: '1.1.1.1', host: 'example.com', port: app.server.address().port })
reply.code(200).send({ ip: req.ip, host: req.host })
})

@@ -99,3 +105,3 @@

test('trust proxy function', (t) => {
t.plan(3)
t.plan(9)
const app = fastify({

@@ -105,4 +111,4 @@ trustProxy: (address) => address === localhost

app.get('/trustproxyfunc', function (req, reply) {
testRequestValues(t, req, { ip: '1.1.1.1' })
reply.code(200).send({ ip: req.ip, hostname: req.hostname })
testRequestValues(t, req, { ip: '1.1.1.1', host: 'example.com', port: app.server.address().port })
reply.code(200).send({ ip: req.ip, host: req.host })
})

@@ -120,3 +126,3 @@

test('trust proxy number', (t) => {
t.plan(4)
t.plan(10)
const app = fastify({

@@ -126,4 +132,4 @@ trustProxy: 1

app.get('/trustproxynumber', function (req, reply) {
testRequestValues(t, req, { ip: '1.1.1.1', ips: [localhost, '1.1.1.1'] })
reply.code(200).send({ ip: req.ip, hostname: req.hostname })
testRequestValues(t, req, { ip: '1.1.1.1', ips: [localhost, '1.1.1.1'], host: 'example.com', port: app.server.address().port })
reply.code(200).send({ ip: req.ip, host: req.host })
})

@@ -141,3 +147,3 @@

test('trust proxy IP addresses', (t) => {
t.plan(4)
t.plan(10)
const app = fastify({

@@ -147,4 +153,4 @@ trustProxy: `${localhost}, 2.2.2.2`

app.get('/trustproxyipaddrs', function (req, reply) {
testRequestValues(t, req, { ip: '1.1.1.1', ips: [localhost, '1.1.1.1'] })
reply.code(200).send({ ip: req.ip, hostname: req.hostname })
testRequestValues(t, req, { ip: '1.1.1.1', ips: [localhost, '1.1.1.1'], host: 'example.com', port: app.server.address().port })
reply.code(200).send({ ip: req.ip, host: req.host })
})

@@ -162,3 +168,3 @@

test('trust proxy protocol', (t) => {
t.plan(13)
t.plan(31)
const app = fastify({

@@ -168,12 +174,12 @@ trustProxy: true

app.get('/trustproxyprotocol', function (req, reply) {
testRequestValues(t, req, { ip: '1.1.1.1', protocol: 'lorem' })
reply.code(200).send({ ip: req.ip, hostname: req.hostname })
testRequestValues(t, req, { ip: '1.1.1.1', protocol: 'lorem', host: 'example.com', port: app.server.address().port })
reply.code(200).send({ ip: req.ip, host: req.host })
})
app.get('/trustproxynoprotocol', function (req, reply) {
testRequestValues(t, req, { ip: '1.1.1.1', protocol: 'http' })
reply.code(200).send({ ip: req.ip, hostname: req.hostname })
testRequestValues(t, req, { ip: '1.1.1.1', protocol: 'http', host: 'example.com', port: app.server.address().port })
reply.code(200).send({ ip: req.ip, host: req.host })
})
app.get('/trustproxyprotocols', function (req, reply) {
testRequestValues(t, req, { ip: '1.1.1.1', protocol: 'dolor' })
reply.code(200).send({ ip: req.ip, hostname: req.hostname })
testRequestValues(t, req, { ip: '1.1.1.1', protocol: 'dolor', host: 'example.com', port: app.server.address().port })
reply.code(200).send({ ip: req.ip, host: req.host })
})

@@ -180,0 +186,0 @@

@@ -62,4 +62,2 @@ import { expectAssignable } from 'tsd'

expectAssignable<FastifyErrorConstructor>(errorCodes.FST_ERR_ASYNC_CONSTRAINT)
expectAssignable<FastifyErrorConstructor>(errorCodes.FST_ERR_DEFAULT_ROUTE_INVALID_TYPE)
expectAssignable<FastifyErrorConstructor>(errorCodes.FST_ERR_INVALID_URL)
expectAssignable<FastifyErrorConstructor>(errorCodes.FST_ERR_ROUTE_OPTIONS_NOT_OBJ)

@@ -66,0 +64,0 @@ expectAssignable<FastifyErrorConstructor>(errorCodes.FST_ERR_ROUTE_DUPLICATED_HANDLER)

@@ -14,3 +14,4 @@ import fastify, {

FastifyErrorCodes,
FastifyError
FastifyError,
SafePromiseLike
} from '../../fastify'

@@ -22,3 +23,2 @@ import { ErrorObject as AjvErrorObject } from 'ajv'

import { expectType, expectError, expectAssignable, expectNotAssignable } from 'tsd'
import { FastifyLoggerInstance } from '../../types/logger'
import { Socket } from 'net'

@@ -28,14 +28,16 @@

// http server
expectType<FastifyInstance<http.Server, http.IncomingMessage, http.ServerResponse> & PromiseLike<FastifyInstance<http.Server, http.IncomingMessage, http.ServerResponse>>>(fastify())
expectType<FastifyInstance<http.Server, http.IncomingMessage, http.ServerResponse> & PromiseLike<FastifyInstance<http.Server, http.IncomingMessage, http.ServerResponse>>>(fastify({}))
expectType<FastifyInstance<http.Server, http.IncomingMessage, http.ServerResponse> & PromiseLike<FastifyInstance<http.Server, http.IncomingMessage, http.ServerResponse>>>(fastify({ http: {} }))
expectError<FastifyInstance<http.Server, http.IncomingMessage, http.ServerResponse> & Promise<FastifyInstance<http.Server, http.IncomingMessage, http.ServerResponse>>>(fastify())
expectAssignable<FastifyInstance<http.Server, http.IncomingMessage, http.ServerResponse> & PromiseLike<FastifyInstance<http.Server, http.IncomingMessage, http.ServerResponse>>>(fastify())
expectType<FastifyInstance<http.Server, http.IncomingMessage, http.ServerResponse> & SafePromiseLike<FastifyInstance<http.Server, http.IncomingMessage, http.ServerResponse>>>(fastify())
expectType<FastifyInstance<http.Server, http.IncomingMessage, http.ServerResponse> & SafePromiseLike<FastifyInstance<http.Server, http.IncomingMessage, http.ServerResponse>>>(fastify({}))
expectType<FastifyInstance<http.Server, http.IncomingMessage, http.ServerResponse> & SafePromiseLike<FastifyInstance<http.Server, http.IncomingMessage, http.ServerResponse>>>(fastify({ http: {} }))
// https server
expectType<FastifyInstance<https.Server, http.IncomingMessage, http.ServerResponse> & PromiseLike<FastifyInstance<https.Server, http.IncomingMessage, http.ServerResponse>>>(fastify({ https: {} }))
expectType<FastifyInstance<https.Server, http.IncomingMessage, http.ServerResponse> & PromiseLike<FastifyInstance<https.Server, http.IncomingMessage, http.ServerResponse>>>(fastify({ https: null }))
expectType<FastifyInstance<https.Server, http.IncomingMessage, http.ServerResponse> & SafePromiseLike<FastifyInstance<https.Server, http.IncomingMessage, http.ServerResponse>>>(fastify({ https: {} }))
expectType<FastifyInstance<https.Server, http.IncomingMessage, http.ServerResponse> & SafePromiseLike<FastifyInstance<https.Server, http.IncomingMessage, http.ServerResponse>>>(fastify({ https: null }))
// http2 server
expectType<FastifyInstance<http2.Http2Server, http2.Http2ServerRequest, http2.Http2ServerResponse> & PromiseLike<FastifyInstance<http2.Http2Server, http2.Http2ServerRequest, http2.Http2ServerResponse>>>(fastify({ http2: true, http2SessionTimeout: 1000 }))
expectType<FastifyInstance<http2.Http2SecureServer, http2.Http2ServerRequest, http2.Http2ServerResponse> & PromiseLike<FastifyInstance<http2.Http2SecureServer, http2.Http2ServerRequest, http2.Http2ServerResponse>>>(fastify({ http2: true, https: {}, http2SessionTimeout: 1000 }))
expectType<FastifyInstance<http2.Http2Server, http2.Http2ServerRequest, http2.Http2ServerResponse> & SafePromiseLike<FastifyInstance<http2.Http2Server, http2.Http2ServerRequest, http2.Http2ServerResponse>>>(fastify({ http2: true, http2SessionTimeout: 1000 }))
expectType<FastifyInstance<http2.Http2SecureServer, http2.Http2ServerRequest, http2.Http2ServerResponse> & SafePromiseLike<FastifyInstance<http2.Http2SecureServer, http2.Http2ServerRequest, http2.Http2ServerResponse>>>(fastify({ http2: true, https: {}, http2SessionTimeout: 1000 }))
expectType<LightMyRequestChain>(fastify({ http2: true, https: {} }).inject())
expectType<FastifyInstance<https.Server, http.IncomingMessage, http.ServerResponse> & PromiseLike<FastifyInstance<https.Server, http.IncomingMessage, http.ServerResponse>>>(fastify({ schemaController: {} }))
expectType<FastifyInstance<https.Server, http.IncomingMessage, http.ServerResponse> & PromiseLike<FastifyInstance<https.Server, http.IncomingMessage, http.ServerResponse>>>(
expectType<FastifyInstance<https.Server, http.IncomingMessage, http.ServerResponse> & SafePromiseLike<FastifyInstance<https.Server, http.IncomingMessage, http.ServerResponse>>>(fastify({ schemaController: {} }))
expectType<FastifyInstance<https.Server, http.IncomingMessage, http.ServerResponse> & SafePromiseLike<FastifyInstance<https.Server, http.IncomingMessage, http.ServerResponse>>>(
fastify({

@@ -98,3 +100,3 @@ schemaController: {

version: '1.0.0',
hostname: 'localhost',
host: 'localhost',
remoteAddress: '127.0.0.1',

@@ -101,0 +103,0 @@ remotePort: 3000

@@ -17,2 +17,3 @@ import { FastifyError } from '@fastify/error'

// preClose hook types should be exported correctly https://github.com/fastify/fastify/pull/5335
/* eslint-disable @typescript-eslint/no-unused-vars */
preCloseAsyncHookHandler,

@@ -19,0 +20,0 @@ preCloseHookHandler

@@ -0,1 +1,2 @@

/* eslint-disable @typescript-eslint/no-unused-vars */
import { FastifyListenOptions, FastifyLogFn } from '../../fastify'

@@ -1,2 +0,2 @@

import { expectAssignable, expectDeprecated, expectError, expectNotDeprecated, expectType } from 'tsd'
import { expectAssignable, expectError, expectNotDeprecated, expectType } from 'tsd'
import fastify, {

@@ -15,3 +15,2 @@ FastifyBaseLogger,

import { FastifyRequest } from '../../types/request'
import { DefaultRoute } from '../../types/route'
import { FastifySchemaControllerOptions, FastifySchemaCompiler, FastifySerializerCompiler } from '../../types/schema'

@@ -198,44 +197,2 @@ import { AddressInfo } from 'net'

// test listen method callback
expectAssignable<void>(server.listen(3000, '', 0, (err, address) => {
expectType<Error | null>(err)
}))
expectAssignable<void>(server.listen('3000', '', 0, (err, address) => {
expectType<Error | null>(err)
}))
expectAssignable<void>(server.listen(3000, '', (err, address) => {
expectType<Error | null>(err)
}))
expectAssignable<void>(server.listen('3000', '', (err, address) => {
expectType<Error | null>(err)
}))
expectAssignable<void>(server.listen(3000, (err, address) => {
expectType<Error | null>(err)
}))
expectAssignable<void>(server.listen('3000', (err, address) => {
expectType<Error | null>(err)
}))
// test listen method callback types
expectAssignable<void>(server.listen('3000', (err, address) => {
expectAssignable<Error|null>(err)
expectAssignable<string>(address)
}))
// test listen method promise
expectAssignable<PromiseLike<string>>(server.listen(3000))
expectAssignable<PromiseLike<string>>(server.listen('3000'))
expectAssignable<PromiseLike<string>>(server.listen(3000, '', 0))
expectAssignable<PromiseLike<string>>(server.listen('3000', '', 0))
expectAssignable<PromiseLike<string>>(server.listen(3000, ''))
expectAssignable<PromiseLike<string>>(server.listen('3000', ''))
// Test variadic listen signatures Typescript deprecation
expectDeprecated(server.listen(3000))
expectDeprecated(server.listen('3000'))
expectDeprecated(server.listen(3000, '', 0))
expectDeprecated(server.listen('3000', '', 0))
expectDeprecated(server.listen(3000, ''))
expectDeprecated(server.listen('3000', ''))
// test listen opts objects

@@ -284,2 +241,8 @@ expectAssignable<PromiseLike<string>>(server.listen())

}))
expectAssignable<FastifyInstance>(server.ready(async (err) => {
expectType<Error | null>(err)
}))
expectAssignable<Parameters<typeof server.ready>[0]>(async (err) => {
expectType<Error | null>(err)
})

@@ -459,3 +422,3 @@ expectAssignable<void>(server.routing({} as RawRequestDefaultExpression, {} as RawReplyDefaultExpression))

server.decorate('typedTestProperty', null, ['foo'])
server.decorate('typedTestProperty', null)
expectError(server.decorate('typedTestProperty', null))
expectError(server.decorate('typedTestProperty', 'foo'))

@@ -500,3 +463,3 @@ expectError(server.decorate('typedTestProperty', {

server.decorateRequest('typedTestRequestProperty', null, ['foo'])
server.decorateRequest('typedTestRequestProperty', null)
expectError(server.decorateRequest('typedTestRequestProperty', null))
expectError(server.decorateRequest('typedTestRequestProperty', 'foo'))

@@ -541,3 +504,3 @@ expectError(server.decorateRequest('typedTestRequestProperty', {

server.decorateReply('typedTestReplyProperty', null, ['foo'])
server.decorateReply('typedTestReplyProperty', null)
expectError(server.decorateReply('typedTestReplyProperty', null))
expectError(server.decorateReply('typedTestReplyProperty', 'foo'))

@@ -579,7 +542,3 @@ expectError(server.decorateReply('typedTestReplyProperty', {

expectType<boolean>(server.hasPlugin(''))
expectAssignable<DefaultRoute<RawRequestDefaultExpression, RawReplyDefaultExpression>>(server.getDefaultRoute())
expectType<FastifySchemaCompiler<any> | undefined>(server.validatorCompiler)
expectType<FastifySerializerCompiler<any> | undefined>(server.serializerCompiler)

@@ -8,4 +8,3 @@ import { expectAssignable, expectDeprecated, expectError, expectNotAssignable, expectType } from 'tsd'

FastifyReply,
FastifyBaseLogger,
FastifyInstance
FastifyBaseLogger
} from '../../fastify'

@@ -125,4 +124,4 @@ import { Server, IncomingMessage, ServerResponse } from 'http'

const serverWithAutoInferredPino = fastify({
logger: P({
const serverWithLoggerInstance = fastify({
loggerInstance: P({
level: 'info',

@@ -133,4 +132,42 @@ redact: ['x-userinfo']

expectType<P.Logger>(serverWithAutoInferredPino.log)
expectType<P.Logger>(serverWithLoggerInstance.log)
const serverWithPinoConfig = fastify({
logger: {
level: 'info',
serializers: {
req (IncomingMessage) {
expectType<FastifyRequest>(IncomingMessage)
return {
method: 'method',
url: 'url',
version: 'version',
host: 'hostname',
remoteAddress: 'remoteAddress',
remotePort: 80,
other: ''
}
},
res (ServerResponse) {
expectType<ResSerializerReply<Server, FastifyReply>>(ServerResponse)
expectAssignable<Partial<FastifyReply> & Pick<FastifyReply, 'statusCode'>>(ServerResponse)
expectNotAssignable<FastifyReply>(ServerResponse)
return {
statusCode: 'statusCode'
}
},
err (FastifyError) {
return {
other: '',
type: 'type',
message: 'msg',
stack: 'stack'
}
}
}
}
})
expectType<FastifyBaseLogger>(serverWithPinoConfig.log)
const serverAutoInferredFileOption = fastify({

@@ -171,3 +208,3 @@ logger: {

version: 'version',
hostname: 'hostname',
host: 'hostname',
remoteAddress: 'remoteAddress',

@@ -174,0 +211,0 @@ remotePort: 80,

@@ -1,2 +0,2 @@

import fastify, { FastifyInstance, FastifyPluginOptions } from '../../fastify'
import fastify, { FastifyInstance, FastifyPluginOptions, SafePromiseLike } from '../../fastify'
import * as http from 'http'

@@ -45,3 +45,5 @@ import * as https from 'https'

const httpsServer = fastify({ https: {} })
expectType<FastifyInstance<https.Server, http.IncomingMessage, http.ServerResponse> & PromiseLike<FastifyInstance<https.Server, http.IncomingMessage, http.ServerResponse>>>(httpsServer)
expectError<FastifyInstance<https.Server, http.IncomingMessage, http.ServerResponse> & Promise<FastifyInstance<https.Server, http.IncomingMessage, http.ServerResponse>>>(httpsServer)
expectAssignable<FastifyInstance<https.Server, http.IncomingMessage, http.ServerResponse> & PromiseLike<FastifyInstance<https.Server, http.IncomingMessage, http.ServerResponse>>>(httpsServer)
expectType<FastifyInstance<https.Server, http.IncomingMessage, http.ServerResponse> & SafePromiseLike<FastifyInstance<https.Server, http.IncomingMessage, http.ServerResponse>>>(httpsServer)

@@ -65,2 +67,3 @@ // Chainable

/* eslint-disable @typescript-eslint/no-unused-vars */
async function testAsync (): Promise<void> {

@@ -67,0 +70,0 @@ await httpsServer

@@ -75,3 +75,3 @@ import { expectAssignable, expectError, expectType } from 'tsd'

// With Type Provider
type TestTypeProvider = { input: 'test', output: 'test' }
type TestTypeProvider = { schema: 'test', validator: 'test', serializer: 'test' }
const serverWithTypeProvider = fastify().withTypeProvider<TestTypeProvider>()

@@ -119,3 +119,3 @@ type ServerWithTypeProvider = FastifyInstance<Server, IncomingMessage, ServerResponse, FastifyLoggerInstance, TestTypeProvider>

const serverWithTypeProviderAndLogger = fastify({
logger: customLogger
loggerInstance: customLogger
}).withTypeProvider<TestTypeProvider>()

@@ -122,0 +122,0 @@ type ServerWithTypeProviderAndLogger = FastifyInstance<Server, IncomingMessage, ServerResponse, typeof customLogger, TestTypeProvider>

import { Buffer } from 'buffer'
import { expectAssignable, expectDeprecated, expectError, expectType } from 'tsd'
import fastify, { FastifyReplyContext, FastifyReply, FastifyRequest, FastifySchema, FastifySchemaCompiler, FastifyTypeProviderDefault, RawRequestDefaultExpression, RouteHandler, RouteHandlerMethod } from '../../fastify'
import { expectAssignable, expectError, expectType } from 'tsd'
import fastify, { FastifyReplyContext, FastifyReply, FastifyRequest, FastifySchema, FastifyTypeProviderDefault, RawRequestDefaultExpression, RouteHandler, RouteHandlerMethod } from '../../fastify'
import { FastifyInstance } from '../../types/instance'

@@ -25,5 +25,6 @@ import { FastifyLoggerInstance } from '../../types/logger'

expectType<boolean>(reply.sent)
expectType<(hints: Record<string, string | string[]>, callback?: (() => void) | undefined) => void>(reply.writeEarlyHints)
expectType<((payload?: unknown) => FastifyReply)>(reply.send)
expectAssignable<(key: string, value: any) => FastifyReply>(reply.header)
expectAssignable<(values: {[key: string]: any}) => FastifyReply>(reply.headers)
expectAssignable<(values: { [key: string]: any }) => FastifyReply>(reply.headers)
expectAssignable<(key: string) => number | string | string[] | undefined>(reply.getHeader)

@@ -33,7 +34,5 @@ expectAssignable<() => { [key: string]: number | string | string[] | undefined }>(reply.getHeaders)

expectAssignable<(key: string) => boolean>(reply.hasHeader)
expectType<{(statusCode: number, url: string): FastifyReply;(url: string, statusCode?: number): FastifyReply;}>(reply.redirect)
expectType<{ (statusCode: number, url: string): FastifyReply;(url: string, statusCode?: number): FastifyReply; }>(reply.redirect)
expectType<() => FastifyReply>(reply.hijack)
expectType<() => void>(reply.callNotFound)
// Test reply.getResponseTime() deprecation
expectDeprecated(reply.getResponseTime)
expectType<(contentType: string) => FastifyReply>(reply.type)

@@ -48,6 +47,6 @@ expectType<(fn: (payload: any) => string) => FastifyReply>(reply.serializer)

expectAssignable<((httpStatus: string) => DefaultSerializationFunction | undefined)>(reply.getSerializationFunction)
expectAssignable<((schema: {[key: string]: unknown}) => DefaultSerializationFunction | undefined)>(reply.getSerializationFunction)
expectAssignable<((schema: {[key: string]: unknown}, httpStatus?: string) => DefaultSerializationFunction)>(reply.compileSerializationSchema)
expectAssignable<((input: {[key: string]: unknown}, schema: {[key: string]: unknown}, httpStatus?: string) => unknown)>(reply.serializeInput)
expectAssignable<((input: {[key: string]: unknown}, httpStatus: string) => unknown)>(reply.serializeInput)
expectAssignable<((schema: { [key: string]: unknown }) => DefaultSerializationFunction | undefined)>(reply.getSerializationFunction)
expectAssignable<((schema: { [key: string]: unknown }, httpStatus?: string) => DefaultSerializationFunction)>(reply.compileSerializationSchema)
expectAssignable<((input: { [key: string]: unknown }, schema: { [key: string]: unknown }, httpStatus?: string) => unknown)>(reply.serializeInput)
expectAssignable<((input: { [key: string]: unknown }, httpStatus: string) => unknown)>(reply.serializeInput)
}

@@ -171,6 +170,8 @@

/* eslint-disable @typescript-eslint/no-unused-vars */
const httpHeaderHandler: RouteHandlerMethod = function (_request, reply) {
// accept is a header provided by @types/node
reply.getHeader('accept')
reply.getHeaders().accept // eslint-disable-line no-unused-expressions
/* eslint-disable @typescript-eslint/no-unused-expressions */
reply.getHeaders().accept
reply.hasHeader('accept')

@@ -184,3 +185,3 @@ reply.header('accept', 'test')

reply.getHeader('x-fastify-test')
reply.getHeaders()['x-fastify-test'] // eslint-disable-line no-unused-expressions
reply.getHeaders()['x-fastify-test']
reply.hasHeader('x-fastify-test')

@@ -187,0 +188,0 @@ reply.header('x-fastify-test', 'test')

@@ -1,2 +0,2 @@

import { expectAssignable, expectType } from 'tsd'
import { expectAssignable, expectError, expectType } from 'tsd'
import fastify, {

@@ -15,3 +15,4 @@ ContextConfigDefault,

RouteHandler,
RouteHandlerMethod
RouteHandlerMethod,
SafePromiseLike
} from '../../fastify'

@@ -58,3 +59,3 @@ import { FastifyInstance } from '../../types/instance'

type HTTPRequestPart = 'body' | 'query' | 'querystring' | 'params' | 'headers'
type ExpectedGetValidationFunction = (input: {[key: string]: unknown}) => boolean
type ExpectedGetValidationFunction = (input: { [key: string]: unknown }) => boolean

@@ -74,2 +75,4 @@ interface CustomLoggerInterface extends FastifyLoggerInstance {

expectType<string>(request.hostname)
expectType<string>(request.host)
expectType<number>(request.port)
expectType<string>(request.ip)

@@ -100,5 +103,5 @@ expectType<string[] | undefined>(request.ips)

expectAssignable<(httpPart: HTTPRequestPart) => ExpectedGetValidationFunction>(request.getValidationFunction)
expectAssignable<(schema: {[key: string]: unknown}) => ExpectedGetValidationFunction>(request.getValidationFunction)
expectAssignable<(input: {[key: string]: unknown}, schema: {[key: string]: unknown}, httpPart?: HTTPRequestPart) => boolean>(request.validateInput)
expectAssignable<(input: {[key: string]: unknown}, httpPart?: HTTPRequestPart) => boolean>(request.validateInput)
expectAssignable<(schema: { [key: string]: unknown }) => ExpectedGetValidationFunction>(request.getValidationFunction)
expectAssignable<(input: { [key: string]: unknown }, schema: { [key: string]: unknown }, httpPart?: HTTPRequestPart) => boolean>(request.validateInput)
expectAssignable<(input: { [key: string]: unknown }, httpPart?: HTTPRequestPart) => boolean>(request.validateInput)
}

@@ -160,8 +163,16 @@

const serverWithCustomLogger = fastify({ logger: customLogger })
expectType<
const serverWithCustomLogger = fastify({ loggerInstance: customLogger })
expectError<
FastifyInstance<RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, CustomLoggerInterface>
& Promise<FastifyInstance<RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, CustomLoggerInterface>>
>(serverWithCustomLogger)
expectAssignable<
FastifyInstance<RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, CustomLoggerInterface>
& PromiseLike<FastifyInstance<RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, CustomLoggerInterface>>
>(serverWithCustomLogger)
expectType<
FastifyInstance<RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, CustomLoggerInterface>
& SafePromiseLike<FastifyInstance<RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, CustomLoggerInterface>>
>(serverWithCustomLogger)
serverWithCustomLogger.get('/get', getHandlerWithCustomLogger)

@@ -22,3 +22,11 @@ import { FastifyError } from '@fastify/error'

bar: number;
includeMessage?: boolean;
}
/* eslint-disable @typescript-eslint/no-unused-vars */
interface FastifyRequest<RouteGeneric, RawServer, RawRequest, SchemaCompiler, TypeProvider, ContextConfig, Logger, RequestType> {
message: ContextConfig extends { includeMessage: true }
? string
: null;
}
}

@@ -40,5 +48,25 @@

type LowerCaseHTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete' | 'options';
fastify().get(
'/',
{ config: { foo: 'bar', bar: 100, includeMessage: true } },
(req) => {
expectType<string>(req.message)
}
)
['GET', 'POST', 'PUT', 'PATCH', 'HEAD', 'DELETE', 'OPTIONS'].forEach(method => {
fastify().get(
'/',
{ config: { foo: 'bar', bar: 100, includeMessage: false } },
(req) => {
expectType<null>(req.message)
}
)
type LowerCaseHTTPMethods = 'delete' | 'get' | 'head' | 'patch' | 'post' | 'put' |
'options' | 'propfind' | 'proppatch' | 'mkcol' | 'copy' | 'move' | 'lock' |
'unlock' | 'trace' | 'search' | 'mkcalendar' | 'report'
;['DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT', 'OPTIONS', 'PROPFIND',
'PROPPATCH', 'MKCOL', 'COPY', 'MOVE', 'LOCK', 'UNLOCK', 'TRACE', 'SEARCH', 'MKCALENDAR', 'REPORT'
].forEach(method => {
// route method

@@ -45,0 +73,0 @@ expectType<FastifyInstance>(fastify().route({

@@ -73,3 +73,3 @@ import { expectAssignable } from 'tsd'

const app = fastify({
fastify({
jsonShorthand: false,

@@ -90,3 +90,3 @@ schemaController: {

const app = fastify({
fastify({
jsonShorthand: false,

@@ -93,0 +93,0 @@ schemaController: {

@@ -6,3 +6,3 @@ import fastify, { FastifyServerFactory } from '../../fastify'

// Custom Server
type CustomType = void;
type CustomType = void
interface CustomIncomingMessage extends http.IncomingMessage {

@@ -9,0 +9,0 @@ fakeMethod?: () => CustomType;

@@ -7,3 +7,4 @@ import fastify, {

FastifyInstance,
FastifyError
FastifyError,
SafePromiseLike
} from '../../fastify'

@@ -27,3 +28,6 @@ import { expectAssignable, expectError, expectType } from 'tsd'

interface NumberProvider extends FastifyTypeProvider { output: number } // remap all schemas to numbers
interface NumberProvider extends FastifyTypeProvider {
validator: number
serializer: number
} // remap all schemas to numbers

@@ -52,3 +56,3 @@ expectAssignable(server.withTypeProvider<NumberProvider>().get(

interface OverriddenProvider extends FastifyTypeProvider { output: 'inferenced' }
interface OverriddenProvider extends FastifyTypeProvider { validator: 'inferenced' }

@@ -75,3 +79,6 @@ expectAssignable(server.withTypeProvider<OverriddenProvider>().get<{ Body: 'override' }>(

interface TypeBoxProvider extends FastifyTypeProvider { output: this['input'] extends TSchema ? Static<this['input']> : unknown }
interface TypeBoxProvider extends FastifyTypeProvider {
validator: this['schema'] extends TSchema ? Static<this['schema']> : unknown
serializer: this['schema'] extends TSchema ? Static<this['schema']> : unknown
}

@@ -110,3 +117,6 @@ expectAssignable(server.withTypeProvider<TypeBoxProvider>().get(

interface JsonSchemaToTsProvider extends FastifyTypeProvider { output: this['input'] extends JSONSchema ? FromSchema<this['input']> : unknown }
interface JsonSchemaToTsProvider extends FastifyTypeProvider {
validator: this['schema'] extends JSONSchema ? FromSchema<this['schema']> : unknown
serializer: this['schema'] extends JSONSchema ? FromSchema<this['schema']> : unknown
}

@@ -915,3 +925,3 @@ // explicitly setting schema `as const`

expectAssignable(server.withTypeProvider<JsonSchemaToTsProvider>().get<{Reply: boolean}>(
expectAssignable(server.withTypeProvider<JsonSchemaToTsProvider>().get<{ Reply: boolean }>(
'/',

@@ -936,3 +946,3 @@ {

expectAssignable(server.withTypeProvider<JsonSchemaToTsProvider>().get<{Reply: boolean}>(
expectAssignable(server.withTypeProvider<JsonSchemaToTsProvider>().get<{ Reply: boolean }>(
'/',

@@ -965,3 +975,3 @@ {

expectAssignable(server.withTypeProvider<JsonSchemaToTsProvider>().get<{Reply: boolean}>(
expectAssignable(server.withTypeProvider<JsonSchemaToTsProvider>().get<{ Reply: boolean }>(
'/',

@@ -986,3 +996,3 @@ {

expectAssignable(server.withTypeProvider<JsonSchemaToTsProvider>().get<{Reply: boolean}>(
expectAssignable(server.withTypeProvider<JsonSchemaToTsProvider>().get<{ Reply: boolean }>(
'/',

@@ -1015,3 +1025,3 @@ {

interface AuxiliaryPluginProvider extends FastifyTypeProvider { output: 'plugin-auxiliary' }
interface AuxiliaryPluginProvider extends FastifyTypeProvider { validator: 'plugin-auxiliary' }

@@ -1045,3 +1055,3 @@ // Auxiliary plugins may have varying server types per application. Recommendation would be to explicitly remap instance provider context within plugin if required.

interface InlineHandlerProvider extends FastifyTypeProvider { output: 'handler-inline' }
interface InlineHandlerProvider extends FastifyTypeProvider { validator: 'handler-inline' }

@@ -1066,3 +1076,3 @@ // Inline handlers should infer for the request parameters (non-shared)

interface AuxiliaryHandlerProvider extends FastifyTypeProvider { output: this['input'] }
interface AuxiliaryHandlerProvider extends FastifyTypeProvider { validator: 'handler-auxiliary' }

@@ -1084,1 +1094,38 @@ // Auxiliary handlers are likely shared for multiple routes and thus should infer as unknown due to potential varying parameters

))
// -------------------------------------------------------------------
// SafePromiseLike
// -------------------------------------------------------------------
const safePromiseLike = {
then: new Promise<string>(resolve => resolve('')).then,
__linterBrands: 'SafePromiseLike' as const
}
expectAssignable<SafePromiseLike<string>>(safePromiseLike)
expectAssignable<PromiseLike<string>>(safePromiseLike)
expectError<Promise<string>>(safePromiseLike)
// -------------------------------------------------------------------
// Separate Providers
// -------------------------------------------------------------------
interface SeparateProvider extends FastifyTypeProvider {
validator: string
serializer: Date
}
expectAssignable(server.withTypeProvider<SeparateProvider>().get(
'/',
{
schema: {
body: null,
response: {
200: { type: 'string' }
}
}
},
(req, res) => {
expectType<string>(req.body)
res.send(new Date())
}
))

@@ -1,2 +0,2 @@

import { expectAssignable, expectType } from 'tsd'
import { expectAssignable } from 'tsd'
import fastify, { FastifyInstance } from '../../fastify'

@@ -15,1 +15,4 @@

}
hasSymbolDisposeWithUsing()
hasSymbolDispose()

@@ -122,4 +122,4 @@ 'use strict'

handler: (req, reply) => {
reply.send({ hello: 'world', hostname: req.hostname, port: req.port })
t.equal(req.originalUrl, '/this-would-404-without-url-rewrite')
reply.send({ hello: 'world' })
}

@@ -136,3 +136,4 @@ })

t.error(err)
t.same(JSON.parse(body), { hello: 'world' })
const parsedBody = JSON.parse(body)
t.same(parsedBody, { hello: 'world', hostname: 'localhost', port: fastify.server.address().port })
t.equal(response.statusCode, 200)

@@ -139,0 +140,0 @@ })

@@ -8,3 +8,3 @@ 'use strict'

test('use semicolon delimiter default true', t => {
test('use semicolon delimiter default false', t => {
t.plan(4)

@@ -16,3 +16,3 @@

fastify.get('/1234', (req, reply) => {
fastify.get('/1234;foo=bar', (req, reply) => {
reply.send(req.query)

@@ -24,3 +24,2 @@ })

console.log('http://localhost:' + fastify.server.address().port + '/1234;foo=bar')
sget({

@@ -32,5 +31,3 @@ method: 'GET',

t.equal(response.statusCode, 200)
t.same(JSON.parse(body), {
foo: 'bar'
})
t.same(JSON.parse(body), {})
})

@@ -37,0 +34,0 @@ })

@@ -457,3 +457,3 @@ 'use strict'

http.get({
hostname: fastify.server.address().hostname,
host: fastify.server.address().hostname,
port: fastify.server.address().port,

@@ -460,0 +460,0 @@ path: '/',

@@ -7,11 +7,5 @@ 'use strict'

const fs = require('node:fs')
const semver = require('semver')
const { Readable } = require('node:stream')
const { fetch: undiciFetch } = require('undici')
if (semver.lt(process.versions.node, '18.0.0')) {
t.skip('Response or ReadableStream not available, skipping test')
process.exit(0)
}
test('should response with a ReadableStream', async (t) => {

@@ -18,0 +12,0 @@ t.plan(2)

@@ -18,3 +18,3 @@ import { RawServerBase, RawServerDefault, RawRequestDefaultExpression } from './utils'

SchemaCompiler extends FastifySchema = FastifySchema,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault
> = ((request: FastifyRequest<RouteGeneric, RawServer, RawRequest, SchemaCompiler, TypeProvider>, rawBody: RawBody, done: ContentTypeParserDoneFunction) => void)

@@ -31,3 +31,3 @@ | ((request: FastifyRequest<RouteGeneric, RawServer, RawRequest, SchemaCompiler, TypeProvider>, rawBody: RawBody) => Promise<any>)

SchemaCompiler extends FastifySchema = FastifySchema,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault
> = ((request: FastifyRequest<RouteGeneric, RawServer, RawRequest, SchemaCompiler, TypeProvider>, payload: RawRequest) => Promise<any>)

@@ -44,3 +44,3 @@ | ((request: FastifyRequest<RouteGeneric, RawServer, RawRequest, SchemaCompiler, TypeProvider>, payload: RawRequest, done: ContentTypeParserDoneFunction) => void)

SchemaCompiler extends FastifySchema = FastifySchema,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault
> {

@@ -47,0 +47,0 @@ (

import { FastifyRouteConfig } from './route'
import { ContextConfigDefault } from './utils'
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface FastifyContextConfig {

@@ -6,0 +5,0 @@ }

@@ -27,2 +27,3 @@ import { FastifyErrorConstructor } from '@fastify/error'

'FST_ERR_DEC_AFTER_START' |
'FST_ERR_DEC_REFERENCE_TYPE' |
'FST_ERR_HOOK_INVALID_TYPE' |

@@ -29,0 +30,0 @@ 'FST_ERR_HOOK_INVALID_HANDLER' |

@@ -727,3 +727,3 @@ import { Readable } from 'stream'

Logger extends FastifyBaseLogger = FastifyBaseLogger,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault
> {

@@ -741,3 +741,3 @@ (

Logger extends FastifyBaseLogger = FastifyBaseLogger,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault
> {

@@ -757,3 +757,3 @@ (

Logger extends FastifyBaseLogger = FastifyBaseLogger,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault
> {

@@ -771,3 +771,3 @@ (

Logger extends FastifyBaseLogger = FastifyBaseLogger,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault
> {

@@ -786,3 +786,3 @@ (

Logger extends FastifyBaseLogger = FastifyBaseLogger,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault
> {

@@ -815,3 +815,3 @@ (

Logger extends FastifyBaseLogger = FastifyBaseLogger,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault
> {

@@ -818,0 +818,0 @@ (

@@ -12,3 +12,3 @@ import { FastifyError } from '@fastify/error'

import { FastifyRequest } from './request'
import { DefaultRoute, RouteGenericInterface, RouteHandlerMethod, RouteOptions, RouteShorthandMethod } from './route'
import { RouteGenericInterface, RouteHandlerMethod, RouteOptions, RouteShorthandMethod } from './route'
import {

@@ -23,3 +23,4 @@ FastifySchema,

FastifyTypeProvider,
FastifyTypeProviderDefault
FastifyTypeProviderDefault,
SafePromiseLike
} from './type-provider'

@@ -35,3 +36,3 @@ import { ContextConfigDefault, HTTPMethods, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerBase, RawServerDefault } from './utils'

type AsyncFunction = (...args: any) => Promise<any>;
type AsyncFunction = (...args: any) => Promise<any>

@@ -102,3 +103,3 @@ export interface FastifyListenOptions {

// Need to disable "no-use-before-define" to maintain backwards compatibility, as else decorate<Foo> would suddenly mean something new
// eslint-disable-next-line no-use-before-define
T extends (P extends keyof This ? This[P] : unknown),

@@ -116,5 +117,3 @@ P extends string | symbol = string | symbol

(property: string | symbol, value: null): Return;
(property: string | symbol, value: null|undefined, dependencies: string[]): Return;
(property: string | symbol, value: null | undefined, dependencies: string[]): Return;
}

@@ -130,3 +129,3 @@

Logger extends FastifyBaseLogger = FastifyBaseLogger,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault
> {

@@ -146,3 +145,3 @@ server: RawServer;

after(): FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider> & PromiseLike<undefined>;
after(): FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider> & SafePromiseLike<undefined>;
after(afterListener: (err: Error | null) => void): FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider>;

@@ -154,3 +153,3 @@

/** Alias for {@linkcode FastifyInstance.close()} */
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore - type only available for @types/node >=17 or typescript >= 5.2

@@ -180,31 +179,8 @@ [Symbol.asyncDispose](): Promise<undefined>;

/**
* @deprecated Variadic listen method is deprecated. Please use `.listen(optionsObject, callback)` instead. The variadic signature will be removed in `fastify@5`
* @see https://github.com/fastify/fastify/pull/3712
*/
listen(port: number | string, address: string, backlog: number, callback: (err: Error|null, address: string) => void): void;
/**
* @deprecated Variadic listen method is deprecated. Please use `.listen(optionsObject, callback)` instead. The variadic signature will be removed in `fastify@5`
* @see https://github.com/fastify/fastify/pull/3712
*/
listen(port: number | string, address: string, callback: (err: Error|null, address: string) => void): void;
/**
* @deprecated Variadic listen method is deprecated. Please use `.listen(optionsObject, callback)` instead. The variadic signature will be removed in `fastify@5`
* @see https://github.com/fastify/fastify/pull/3712
*/
listen(port: number | string, callback: (err: Error|null, address: string) => void): void;
/**
* @deprecated Variadic listen method is deprecated. Please use `.listen(optionsObject)` instead. The variadic signature will be removed in `fastify@5`
* @see https://github.com/fastify/fastify/pull/3712
*/
listen(port: number | string, address?: string, backlog?: number): Promise<string>;
ready(): FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider> & SafePromiseLike<undefined>;
ready(readyListener: (err: Error | null) => void | Promise<void>): FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider>;
ready(): FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider> & PromiseLike<undefined>;
ready(readyListener: (err: Error | null) => void): FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider>;
register: FastifyRegister<FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider> & SafePromiseLike<undefined>>;
register: FastifyRegister<FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider> & PromiseLike<undefined>>;
routing(req: RawRequest, res: RawReply): void;
getDefaultRoute(): DefaultRoute<RawRequest, RawReply>;
setDefaultRoute(defaultRoute: DefaultRoute<RawRequest, RawReply>): void;

@@ -214,12 +190,23 @@ route<

ContextConfig = ContextConfigDefault,
const SchemaCompiler extends FastifySchema = FastifySchema,
const SchemaCompiler extends FastifySchema = FastifySchema
>(opts: RouteOptions<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, Logger>): FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider>;
delete: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
get: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
head: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
patch: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
post: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
put: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
delete: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
options: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
patch: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
propfind: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
proppatch: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
mkcalendar: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
mkcol: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
copy: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
move: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
lock: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
unlock: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
trace: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
report: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
search: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;
all: RouteShorthandMethod<RawServer, RawRequest, RawReply, TypeProvider, Logger>;

@@ -230,3 +217,3 @@

ContextConfig = ContextConfigDefault,
SchemaCompiler extends FastifySchema = FastifySchema,
SchemaCompiler extends FastifySchema = FastifySchema
>(opts: Pick<RouteOptions<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider>, 'method' | 'url' | 'constraints'>): boolean;

@@ -237,3 +224,3 @@

ContextConfig = ContextConfigDefault,
SchemaCompiler extends FastifySchema = FastifySchema,
SchemaCompiler extends FastifySchema = FastifySchema
>(opts: Pick<RouteOptions<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider>, 'method' | 'url' | 'constraints'>): Omit<FindMyWayFindResult<RawServer>, 'store'>;

@@ -240,0 +227,0 @@

@@ -46,3 +46,3 @@ import { FastifyError } from '@fastify/error'

RawReply extends FastifyReply<RawServer>
> = Partial<RawReply> & Pick<RawReply, 'statusCode'>;
> = Partial<RawReply> & Pick<RawReply, 'statusCode'>

@@ -55,3 +55,3 @@ /**

RawRequest extends FastifyRequest<RouteGenericInterface, RawServer, RawRequestDefaultExpression<RawServer>, FastifySchema, FastifyTypeProvider> = FastifyRequest<RouteGenericInterface, RawServer, RawRequestDefaultExpression<RawServer>, FastifySchema, FastifyTypeProviderDefault>,
RawReply extends FastifyReply<RawServer, RawRequestDefaultExpression<RawServer>, RawReplyDefaultExpression<RawServer>, RouteGenericInterface, ContextConfigDefault, FastifySchema, FastifyTypeProvider> = FastifyReply<RawServer, RawRequestDefaultExpression<RawServer>, RawReplyDefaultExpression<RawServer>, RouteGenericInterface, ContextConfigDefault, FastifySchema, FastifyTypeProviderDefault>,
RawReply extends FastifyReply<RawServer, RawRequestDefaultExpression<RawServer>, RawReplyDefaultExpression<RawServer>, RouteGenericInterface, ContextConfigDefault, FastifySchema, FastifyTypeProvider> = FastifyReply<RawServer, RawRequestDefaultExpression<RawServer>, RawReplyDefaultExpression<RawServer>, RouteGenericInterface, ContextConfigDefault, FastifySchema, FastifyTypeProviderDefault>
> {

@@ -63,3 +63,3 @@ serializers?: {

version?: string;
hostname?: string;
host?: string;
remoteAddress?: string;

@@ -66,0 +66,0 @@ remotePort?: number;

@@ -17,3 +17,3 @@ import { FastifyInstance } from './instance'

TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
Logger extends FastifyBaseLogger = FastifyBaseLogger,
Logger extends FastifyBaseLogger = FastifyBaseLogger
> = (

@@ -34,7 +34,7 @@ instance: FastifyInstance<Server, RawRequestDefaultExpression<Server>, RawReplyDefaultExpression<Server>, Logger, TypeProvider>,

TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
Logger extends FastifyBaseLogger = FastifyBaseLogger,
Logger extends FastifyBaseLogger = FastifyBaseLogger
> = (
instance: FastifyInstance<Server, RawRequestDefaultExpression<Server>, RawReplyDefaultExpression<Server>, Logger, TypeProvider>,
opts: Options
) => Promise<void>;
) => Promise<void>

@@ -41,0 +41,0 @@ /**

@@ -8,3 +8,3 @@ import { Buffer } from 'buffer'

import { FastifySchema } from './schema'
import { FastifyReplyType, FastifyTypeProvider, FastifyTypeProviderDefault, ResolveFastifyReplyType, CallTypeProvider } from './type-provider'
import { CallSerializerTypeProvider, FastifyReplyType, FastifyTypeProvider, FastifyTypeProviderDefault, ResolveFastifyReplyType } from './type-provider'
import { CodeToReplyKey, ContextConfigDefault, HttpKeys, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerBase, RawServerDefault, ReplyDefault, ReplyKeysToCodes, HttpHeader } from './utils'

@@ -22,3 +22,3 @@

CodeToReplyKey<Code> extends keyof RouteGenericReply ? RouteGenericReply[CodeToReplyKey<Code>] : unknown :
RouteGenericReply;
RouteGenericReply

@@ -29,3 +29,3 @@ export type ResolveReplyTypeWithRouteGeneric<RouteGenericReply, Code extends ReplyKeysToCodes<keyof RouteGenericReply>,

Code extends keyof SchemaCompiler['response'] ?
CallTypeProvider<TypeProvider, SchemaCompiler['response'][Code]> :
CallSerializerTypeProvider<TypeProvider, SchemaCompiler['response'][Code]> :
ResolveFastifyReplyType<TypeProvider, SchemaCompiler, { Reply: ReplyTypeConstrainer<RouteGenericReply, Code> }>

@@ -68,8 +68,5 @@ /**

redirect(url: string, statusCode?: number): FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider>;
writeEarlyHints(hints: Record<string, string | string[]>, callback?: () => void): void;
hijack(): FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider>;
callNotFound(): void;
/**
* @deprecated Use the Reply#elapsedTime property instead
*/
getResponseTime(): number;
type(contentType: string): FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider>;

@@ -79,7 +76,7 @@ serializer(fn: (payload: any) => string): FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider>;

// Serialization Methods
getSerializationFunction(httpStatus: string, contentType?: string): ((payload: {[key: string]: unknown}) => string) | undefined;
getSerializationFunction(schema: {[key: string]: unknown}): ((payload: {[key: string]: unknown}) => string) | undefined;
compileSerializationSchema(schema: {[key: string]: unknown}, httpStatus?: string, contentType?: string): (payload: {[key: string]: unknown}) => string;
serializeInput(input: {[key: string]: unknown}, schema: {[key: string]: unknown}, httpStatus?: string, contentType?: string): string;
serializeInput(input: {[key: string]: unknown}, httpStatus: string, contentType?: string): unknown;
getSerializationFunction(httpStatus: string, contentType?: string): ((payload: { [key: string]: unknown }) => string) | undefined;
getSerializationFunction(schema: { [key: string]: unknown }): ((payload: { [key: string]: unknown }) => string) | undefined;
compileSerializationSchema(schema: { [key: string]: unknown }, httpStatus?: string, contentType?: string): (payload: { [key: string]: unknown }) => string;
serializeInput(input: { [key: string]: unknown }, schema: { [key: string]: unknown }, httpStatus?: string, contentType?: string): string;
serializeInput(input: { [key: string]: unknown }, httpStatus: string, contentType?: string): unknown;
then(fulfilled: () => void, rejected: (err: Error) => void): void;

@@ -86,0 +83,0 @@ trailer: (

@@ -78,2 +78,4 @@ import { ErrorObject } from '@fastify/ajv-compiler'

readonly ips?: string[];
readonly host: string;
readonly port: number;
readonly hostname: string;

@@ -91,5 +93,5 @@ readonly url: string;

getValidationFunction(httpPart: HTTPRequestPart): ValidationFunction
getValidationFunction(schema: {[key: string]: any}): ValidationFunction
compileValidationSchema(schema: {[key: string]: any}, httpPart?: HTTPRequestPart): ValidationFunction
validateInput(input: any, schema: {[key: string]: any}, httpPart?: HTTPRequestPart): boolean
getValidationFunction(schema: { [key: string]: any }): ValidationFunction
compileValidationSchema(schema: { [key: string]: any }, httpPart?: HTTPRequestPart): ValidationFunction
validateInput(input: any, schema: { [key: string]: any }, httpPart?: HTTPRequestPart): boolean
validateInput(input: any, httpPart?: HTTPRequestPart): boolean

@@ -96,0 +98,0 @@

import { FastifyError } from '@fastify/error'
import { ConstraintStrategy } from 'find-my-way'
import { FastifyRequestContext } from './context'
import { FastifyContextConfig } from './context'
import { onErrorMetaHookHandler, onRequestAbortMetaHookHandler, onRequestMetaHookHandler, onResponseMetaHookHandler, onSendMetaHookHandler, onTimeoutMetaHookHandler, preHandlerMetaHookHandler, preParsingMetaHookHandler, preSerializationMetaHookHandler, preValidationMetaHookHandler } from './hooks'

@@ -15,3 +15,3 @@ import { FastifyInstance } from './instance'

} from './type-provider'
import { ContextConfigDefault, HTTPMethods, NoInferCompat, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerBase, RawServerDefault } from './utils'
import { ContextConfigDefault, HTTPMethods, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerBase, RawServerDefault } from './utils'

@@ -52,15 +52,15 @@ export interface FastifyRouteConfig {

validatorCompiler?: FastifySchemaCompiler<NoInferCompat<SchemaCompiler>>;
serializerCompiler?: FastifySerializerCompiler<NoInferCompat<SchemaCompiler>>;
validatorCompiler?: FastifySchemaCompiler<NoInfer<SchemaCompiler>>;
serializerCompiler?: FastifySerializerCompiler<NoInfer<SchemaCompiler>>;
bodyLimit?: number;
logLevel?: LogLevel;
config?: Omit<FastifyRequestContext<ContextConfig>['config'], 'url' | 'method'>;
config?: FastifyContextConfig & ContextConfig;
version?: string;
constraints?: RouteConstraint,
prefixTrailingSlash?: 'slash'|'no-slash'|'both';
prefixTrailingSlash?: 'slash' | 'no-slash' | 'both';
errorHandler?: (
this: FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider>,
error: FastifyError,
request: FastifyRequest<RouteGeneric, RawServer, RawRequest, NoInferCompat<SchemaCompiler>, TypeProvider, ContextConfig, Logger>,
reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInferCompat<SchemaCompiler>, TypeProvider>
request: FastifyRequest<RouteGeneric, RawServer, RawRequest, NoInfer<SchemaCompiler>, TypeProvider, ContextConfig, Logger>,
reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInfer<SchemaCompiler>, TypeProvider>
) => void;

@@ -71,22 +71,22 @@ childLoggerFactory?: FastifyChildLoggerFactory<RawServer, RawRequest, RawReply, Logger, TypeProvider>;

// hooks
onRequest?: onRequestMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInferCompat<SchemaCompiler>, TypeProvider, Logger>
| onRequestMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInferCompat<SchemaCompiler>, TypeProvider, Logger>[];
preParsing?: preParsingMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInferCompat<SchemaCompiler>, TypeProvider, Logger>
| preParsingMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInferCompat<SchemaCompiler>, TypeProvider, Logger>[];
preValidation?: preValidationMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInferCompat<SchemaCompiler>, TypeProvider, Logger>
| preValidationMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInferCompat<SchemaCompiler>, TypeProvider, Logger>[];
preHandler?: preHandlerMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInferCompat<SchemaCompiler>, TypeProvider, Logger>
| preHandlerMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInferCompat<SchemaCompiler>, TypeProvider, Logger>[];
preSerialization?: preSerializationMetaHookHandler<unknown, RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInferCompat<SchemaCompiler>, TypeProvider, Logger>
| preSerializationMetaHookHandler<unknown, RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInferCompat<SchemaCompiler>, TypeProvider, Logger>[];
onSend?: onSendMetaHookHandler<unknown, RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInferCompat<SchemaCompiler>, TypeProvider, Logger>
| onSendMetaHookHandler<unknown, RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInferCompat<SchemaCompiler>, TypeProvider, Logger>[];
onResponse?: onResponseMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInferCompat<SchemaCompiler>, TypeProvider, Logger>
| onResponseMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInferCompat<SchemaCompiler>, TypeProvider, Logger>[];
onTimeout?: onTimeoutMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInferCompat<SchemaCompiler>, TypeProvider, Logger>
| onTimeoutMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInferCompat<SchemaCompiler>, TypeProvider, Logger>[];
onError?: onErrorMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, FastifyError, NoInferCompat<SchemaCompiler>, TypeProvider, Logger>
| onErrorMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, FastifyError, NoInferCompat<SchemaCompiler>, TypeProvider, Logger>[];
onRequestAbort?: onRequestAbortMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInferCompat<SchemaCompiler>, TypeProvider, Logger>
| onRequestAbortMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInferCompat<SchemaCompiler>, TypeProvider, Logger>[];
onRequest?: onRequestMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInfer<SchemaCompiler>, TypeProvider, Logger>
| onRequestMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInfer<SchemaCompiler>, TypeProvider, Logger>[];
preParsing?: preParsingMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInfer<SchemaCompiler>, TypeProvider, Logger>
| preParsingMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInfer<SchemaCompiler>, TypeProvider, Logger>[];
preValidation?: preValidationMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInfer<SchemaCompiler>, TypeProvider, Logger>
| preValidationMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInfer<SchemaCompiler>, TypeProvider, Logger>[];
preHandler?: preHandlerMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInfer<SchemaCompiler>, TypeProvider, Logger>
| preHandlerMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInfer<SchemaCompiler>, TypeProvider, Logger>[];
preSerialization?: preSerializationMetaHookHandler<unknown, RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInfer<SchemaCompiler>, TypeProvider, Logger>
| preSerializationMetaHookHandler<unknown, RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInfer<SchemaCompiler>, TypeProvider, Logger>[];
onSend?: onSendMetaHookHandler<unknown, RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInfer<SchemaCompiler>, TypeProvider, Logger>
| onSendMetaHookHandler<unknown, RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInfer<SchemaCompiler>, TypeProvider, Logger>[];
onResponse?: onResponseMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInfer<SchemaCompiler>, TypeProvider, Logger>
| onResponseMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInfer<SchemaCompiler>, TypeProvider, Logger>[];
onTimeout?: onTimeoutMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInfer<SchemaCompiler>, TypeProvider, Logger>
| onTimeoutMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInfer<SchemaCompiler>, TypeProvider, Logger>[];
onError?: onErrorMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, FastifyError, NoInfer<SchemaCompiler>, TypeProvider, Logger>
| onErrorMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, FastifyError, NoInfer<SchemaCompiler>, TypeProvider, Logger>[];
onRequestAbort?: onRequestAbortMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInfer<SchemaCompiler>, TypeProvider, Logger>
| onRequestAbortMetaHookHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInfer<SchemaCompiler>, TypeProvider, Logger>[];
}

@@ -125,3 +125,3 @@ /**

> extends RouteShorthandOptions<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, Logger> {
handler: RouteHandlerMethod<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, Logger>;
handler: RouteHandlerMethod<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInfer<SchemaCompiler>, TypeProvider, Logger>;
}

@@ -169,3 +169,3 @@

url: string;
handler: RouteHandlerMethod<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, NoInferCompat<SchemaCompiler>, TypeProvider, Logger>;
handler: RouteHandlerMethod<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, Logger>;
}

@@ -191,2 +191,2 @@

res: Reply,
) => void;
) => void
import { ValidatorFactory } from '@fastify/ajv-compiler'
import { SerializerFactory } from '@fastify/fast-json-stringify-compiler'
import { FastifyInstance } from '../fastify'
import { FastifyInstance, SafePromiseLike } from '../fastify'
/**

@@ -36,3 +36,3 @@ * Schemas in Fastify follow the JSON-Schema standard. For this reason

export interface FastifyValidationResult {
(data: any): boolean | PromiseLike<any> | { error?: Error, value?: any }
(data: any): boolean | SafePromiseLike<any> | { error?: Error, value?: any }
errors?: FastifySchemaValidationError[] | null;

@@ -48,3 +48,3 @@ }

export interface FastifySchemaControllerOptions{
export interface FastifySchemaControllerOptions {
bucket?: (parentSchemas?: unknown) => {

@@ -51,0 +51,0 @@ add(schema: unknown): FastifyInstance;

@@ -12,4 +12,4 @@ import { RawServerBase, RawServerDefault, RawReplyDefaultExpression, RawRequestDefaultExpression } from './utils'

RawServer extends http.Server | https.Server ?
(request: http.IncomingMessage & RawRequest, response: http.ServerResponse & RawReply) => void :
(request: http2.Http2ServerRequest & RawRequest, response: http2.Http2ServerResponse & RawReply) => void
(request: http.IncomingMessage & RawRequest, response: http.ServerResponse & RawReply) => void :
(request: http2.Http2ServerRequest & RawRequest, response: http2.Http2ServerResponse & RawReply) => void

@@ -16,0 +16,0 @@ export interface FastifyServerFactory<

@@ -10,10 +10,11 @@ import { RouteGenericInterface } from './route'

export interface FastifyTypeProvider {
readonly input: unknown,
readonly output: unknown,
readonly schema: unknown,
readonly validator: unknown,
readonly serializer: unknown,
}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface FastifyTypeProviderDefault extends FastifyTypeProvider {}
export type CallTypeProvider<F extends FastifyTypeProvider, I> = (F & { input: I })['output']
export type CallValidatorTypeProvider<F extends FastifyTypeProvider, S> = (F & { schema: S })['validator']
export type CallSerializerTypeProvider<F extends FastifyTypeProvider, S> = (F & { schema: S })['serializer']

@@ -36,9 +37,9 @@ // -----------------------------------------------------------------------------------------------

type ResolveRequestParams<TypeProvider extends FastifyTypeProvider, SchemaCompiler extends FastifySchema, RouteGeneric extends RouteGenericInterface> =
UndefinedToUnknown<KeysOf<RouteGeneric['Params']> extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['params']> : RouteGeneric['Params']>
UndefinedToUnknown<KeysOf<RouteGeneric['Params']> extends never ? CallValidatorTypeProvider<TypeProvider, SchemaCompiler['params']> : RouteGeneric['Params']>
type ResolveRequestQuerystring<TypeProvider extends FastifyTypeProvider, SchemaCompiler extends FastifySchema, RouteGeneric extends RouteGenericInterface> =
UndefinedToUnknown<KeysOf<RouteGeneric['Querystring']> extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['querystring']> : RouteGeneric['Querystring']>
UndefinedToUnknown<KeysOf<RouteGeneric['Querystring']> extends never ? CallValidatorTypeProvider<TypeProvider, SchemaCompiler['querystring']> : RouteGeneric['Querystring']>
type ResolveRequestHeaders<TypeProvider extends FastifyTypeProvider, SchemaCompiler extends FastifySchema, RouteGeneric extends RouteGenericInterface> =
UndefinedToUnknown<KeysOf<RouteGeneric['Headers']> extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['headers']> : RouteGeneric['Headers']>
UndefinedToUnknown<KeysOf<RouteGeneric['Headers']> extends never ? CallValidatorTypeProvider<TypeProvider, SchemaCompiler['headers']> : RouteGeneric['Headers']>
type ResolveRequestBody<TypeProvider extends FastifyTypeProvider, SchemaCompiler extends FastifySchema, RouteGeneric extends RouteGenericInterface> =
UndefinedToUnknown<KeysOf<RouteGeneric['Body']> extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['body']> : RouteGeneric['Body']>
UndefinedToUnknown<KeysOf<RouteGeneric['Body']> extends never ? CallValidatorTypeProvider<TypeProvider, SchemaCompiler['body']> : RouteGeneric['Body']>

@@ -68,4 +69,4 @@ // The target request type. This type is inferenced on fastify 'requests' via generic argument assignment

[K1 in keyof SchemaCompiler['response']]: SchemaCompiler['response'][K1] extends { content: { [keyof: string]: { schema: unknown } } } ? ({
[K2 in keyof SchemaCompiler['response'][K1]['content']]: CallTypeProvider<TypeProvider, SchemaCompiler['response'][K1]['content'][K2]['schema']>
} extends infer Result ? Result[keyof Result] : unknown) : CallTypeProvider<TypeProvider, SchemaCompiler['response'][K1]>
[K2 in keyof SchemaCompiler['response'][K1]['content']]: CallSerializerTypeProvider<TypeProvider, SchemaCompiler['response'][K1]['content'][K2]['schema']>
} extends infer Result ? Result[keyof Result] : unknown) : CallSerializerTypeProvider<TypeProvider, SchemaCompiler['response'][K1]>
} extends infer Result ? Result[keyof Result] : unknown;

@@ -89,3 +90,3 @@

SchemaCompiler extends FastifySchema,
RouteGeneric extends RouteGenericInterface,
RouteGeneric extends RouteGenericInterface
> = ResolveFastifyReplyType<

@@ -96,5 +97,14 @@ TypeProvider,

> extends infer Return ?
(Return | void | Promise<Return | void>)
(Return | void | Promise<Return | void>)
// review: support both async and sync return types
// (Promise<Return> | Return | Promise<void> | void)
: unknown
/**
* This branded type is needed to indicate APIs that return Promise-likes which can
* safely "float" (not have rejections handled by calling code).
*
* Please refer to the following Github issue for more info:
* https://github.com/fastify/fastify/issues/5498
*/
export type SafePromiseLike<T> = PromiseLike<T> & { __linterBrands: 'SafePromiseLike' }

@@ -27,3 +27,3 @@ import * as http from 'http'

export type RawRequestDefaultExpression<
RawServer extends RawServerBase = RawServerDefault,
RawServer extends RawServerBase = RawServerDefault
> = RawServer extends http.Server | https.Server ? http.IncomingMessage

@@ -54,11 +54,11 @@ : RawServer extends http2.Http2Server | http2.Http2SecureServer ? http2.Http2ServerRequest

type StringAsNumber<T extends string> = T extends `${infer N extends number}` ? N : never;
type CodeClasses = 1 | 2 | 3 | 4 | 5;
type Digit = 0 |1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
type HttpCodes = StringAsNumber<`${CodeClasses}${Digit}${Digit}`>;
type HttpKeys = HttpCodes | `${Digit}xx`;
type StringAsNumber<T extends string> = T extends `${infer N extends number}` ? N : never
type CodeClasses = 1 | 2 | 3 | 4 | 5
type Digit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
type HttpCodes = StringAsNumber<`${CodeClasses}${Digit}${Digit}`>
type HttpKeys = HttpCodes | `${Digit}xx`
export type StatusCodeReply = {
// eslint-disable-next-line no-unused-vars
[Key in HttpKeys]?: unknown;
};
}

@@ -69,20 +69,20 @@ // weird TS quirk: https://stackoverflow.com/questions/58977876/generic-conditional-type-resolves-to-never-when-the-generic-type-is-set-to-never

Key extends `${infer X extends CodeClasses}xx` ?
StringAsNumber<`${X}${Digit}${Digit}`> : number;
StringAsNumber<`${X}${Digit}${Digit}`> : number
export type CodeToReplyKey<Code extends number> = `${Code}` extends `${infer FirstDigit extends CodeClasses}${number}`
? `${FirstDigit}xx`
: never;
: never
export type RecordKeysToLowercase<Input> = Input extends Record<string, unknown>
? {
[Key in keyof Input as Key extends string
? Lowercase<Key>
: Key
]: Input[Key];
}
: Input;
[Key in keyof Input as Key extends string
? Lowercase<Key>
: Key
]: Input[Key];
}
: Input
type OmitIndexSignature<T> = {
[K in keyof T as string extends K ? never : number extends K ? never : K]: T[K];
};
}

@@ -93,7 +93,2 @@ /**

*/
export type HttpHeader = keyof OmitIndexSignature<http.OutgoingHttpHeaders> | (string & Record<never, never>);
// cheat for similar (same?) behavior as NoInfer but for TS <5.4
export type NoInferCompat<SC> = {
[K in keyof SC]: SC[K]
};
export type HttpHeader = keyof OmitIndexSignature<http.OutgoingHttpHeaders> | (string & Record<never, never>)

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc