Comparing version 4.28.0 to 5.0.0-alpha.2
@@ -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 */ |
@@ -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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
37
3072203
529
60174
1
413
8
+ Addeddc-polyfill@^0.1.6
+ Addeddc-polyfill@0.1.6(transitive)
- Removedfast-content-type-parse@^1.1.0
- Removedfast-content-type-parse@1.1.0(transitive)
Updated@fastify/error@^3.4.1
Updatedfast-json-stringify@^5.14.1
Updatedfind-my-way@^8.1.0
Updatedlight-my-request@^5.13.0
Updatedrfdc@^1.3.1
Updatedsemver@^7.6.0
Updatedtoad-cache@^3.7.0