Comparing version 4.6.0 to 4.7.0
@@ -83,2 +83,4 @@ <h1 align="center">Fastify</h1> | ||
[`simple-oauth2`](https://github.com/lelylan/simple-oauth2). | ||
- [`@fastify/one-line-logger`](https://github.com/fastify/one-line-logger) Formats | ||
Fastify's logs into a nice one-line message. | ||
- [`@fastify/postgres`](https://github.com/fastify/fastify-postgres) Fastify | ||
@@ -123,6 +125,6 @@ PostgreSQL connection plugin, with this you can share the same PostgreSQL | ||
[type provider](https://www.fastify.io/docs/latest/Reference/Type-Providers/) | ||
for [json-schema-to-ts](https://github.com/ThomasAribart/json-schema-to-ts). | ||
for [json-schema-to-ts](https://github.com/ThomasAribart/json-schema-to-ts). | ||
- [`@fastify/type-provider-typebox`](https://github.com/fastify/fastify-type-provider-typebox) | ||
Fastify | ||
[type provider](https://www.fastify.io/docs/latest/Reference/Type-Providers/) | ||
[type provider](https://www.fastify.io/docs/latest/Reference/Type-Providers/) | ||
for [Typebox](https://github.com/sinclairzx81/typebox). | ||
@@ -172,3 +174,3 @@ - [`@fastify/under-pressure`](https://github.com/fastify/under-pressure) Measure | ||
- [`@mateonunez/fastify-lyra`](https://github.com/mateonunez/fastify-lyra) | ||
A plugin to implement [Lyra](https://github.com/nearform/lyra) search engine | ||
A plugin to implement [Lyra](https://github.com/nearform/lyra) search engine | ||
on Fastify | ||
@@ -197,3 +199,3 @@ - [`@mgcrea/fastify-graceful-exit`](https://github.com/mgcrea/fastify-graceful-exit) | ||
request IDs into your logs. | ||
- [`electron-server`](https://github.com/anonrig/electron-server) A plugin for | ||
- [`electron-server`](https://github.com/anonrig/electron-server) A plugin for | ||
using Fastify without the need of consuming a port on Electron apps. | ||
@@ -453,3 +455,3 @@ - [`fast-water`](https://github.com/tswayne/fast-water) A Fastify plugin for | ||
- [`fastify-osm`](https://github.com/gzileni/fastify-osm) Fastify | ||
OSM plugin to run overpass queries by OpenStreetMap. | ||
OSM plugin to run overpass queries by OpenStreetMap. | ||
- [`fastify-peekaboo`](https://github.com/simone-sanfratello/fastify-peekaboo) | ||
@@ -479,2 +481,5 @@ Fastify plugin for memoize responses by expressive settings. | ||
plugin that adds support to handle an aborted request asynchronous. | ||
- [`fastify-ravendb`](https://github.com/nearform/fastify-ravendb) RavenDB | ||
connection plugin. It exposes the same `DocumentStore` (or multiple ones) | ||
across the whole Fastify application. | ||
- [`fastify-raw-body`](https://github.com/Eomm/fastify-raw-body) Add the | ||
@@ -505,3 +510,5 @@ `request.rawBody` field. | ||
- [`fastify-route-group`](https://github.com/TakNePoidet/fastify-route-group) | ||
Convenient grouping and inheritance of routes | ||
Convenient grouping and inheritance of routes. | ||
- [`fastify-s3-buckets`](https://github.com/kibertoad/fastify-s3-buckets) | ||
Ensure the existence of defined S3 buckets on the application startup. | ||
- [`fastify-schema-constraint`](https://github.com/Eomm/fastify-schema-constraint) | ||
@@ -522,2 +529,4 @@ Choose the JSON schema to use based on request parameters. | ||
plugin, with this you can use slonik in every part of your server. | ||
- [`fastify-slow-down`](https://github.com/nearform/fastify-slow-down) A plugin | ||
to delay the response from the server. | ||
- [`fastify-socket.io`](https://github.com/alemagio/fastify-socket.io) a | ||
@@ -528,2 +537,4 @@ Socket.io plugin for Fastify. | ||
HTTP part of the request. | ||
- [`fastify-sqlite`](https://github.com/Eomm/fastify-sqlite) connects your | ||
application to a sqlite3 database. | ||
- [`fastify-sse`](https://github.com/lolo32/fastify-sse) to provide Server-Sent | ||
@@ -553,4 +564,4 @@ Events with `reply.sse( … )` to Fastify. | ||
- [`fastify-type-provider-zod`](https://github.com/turkerdev/fastify-type-provider-zod) | ||
Fastify | ||
[type provider](https://www.fastify.io/docs/latest/Reference/Type-Providers/) | ||
Fastify | ||
[type provider](https://www.fastify.io/docs/latest/Reference/Type-Providers/) | ||
for [zod](https://github.com/colinhacks/zod). | ||
@@ -557,0 +568,0 @@ - [`fastify-typeorm-plugin`](https://github.com/inthepocket/fastify-typeorm-plugin) |
@@ -311,2 +311,46 @@ <h1 align="center">Fastify</h1> | ||
An alternative approach is to make use of the [onRoute hook](../Reference/Hooks.md#onroute) | ||
to customize application routes dynamically from inside the plugin. Every time | ||
a new route is registered, you can read and modify the route options. For example, | ||
based on a [route config option](../Reference/Routes.md#routes-options): | ||
```js | ||
fastify.register((instance, opts, done) => { | ||
instance.decorate('util', (request, key, value) => { request[key] = value }) | ||
function handler(request, reply, done) { | ||
instance.util(request, 'timestamp', new Date()) | ||
done() | ||
} | ||
instance.addHook('onRoute', (routeOptions) => { | ||
if (routeOptions.config && routeOptions.config.useUtil === true) { | ||
// set or add our handler to the route preHandler hook | ||
if (!routeOptions.preHandler) { | ||
routeOptions.preHandler = [handler] | ||
return | ||
} | ||
if (Array.isArray(routeOptions.preHandler)) { | ||
routeOptions.preHandler.push(handler) | ||
return | ||
} | ||
routeOptions.preHandler = [routeOptions.preHandler, handler] | ||
} | ||
}) | ||
fastify.get('/plugin1', {config: {useUtil: true}}, (request, reply) => { | ||
reply.send(request) | ||
}) | ||
fastify.get('/plugin2', (request, reply) => { | ||
reply.send(request) | ||
}) | ||
done() | ||
}) | ||
``` | ||
This variant becomes extremely useful if you plan to distribute your plugin, as | ||
described in the next section. | ||
As you probably noticed by now, `request` and `reply` are not the standard | ||
@@ -313,0 +357,0 @@ Nodejs *request* and *response* objects, but Fastify's objects. |
@@ -10,6 +10,6 @@ <h1 align="center">Fastify</h1> | ||
- [.header(key, value)](#headerkey-value) | ||
- [set-cookie](#set-cookie) | ||
- [.headers(object)](#headersobject) | ||
- [.getHeader(key)](#getheaderkey) | ||
- [.getHeaders()](#getheaders) | ||
- [set-cookie](#set-cookie) | ||
- [.removeHeader(key)](#removeheaderkey) | ||
@@ -20,9 +20,9 @@ - [.hasHeader(key)](#hasheaderkey) | ||
- [.removeTrailer(key)](#removetrailerkey) | ||
- [.redirect([code,] dest)](#redirectcode--dest) | ||
- [.redirect([code ,] dest)](#redirectcode--dest) | ||
- [.callNotFound()](#callnotfound) | ||
- [.getResponseTime()](#getresponsetime) | ||
- [.type(contentType)](#typecontenttype) | ||
- [.getSerializationFunction(schema | httpStatus)](#getserializationfunction) | ||
- [.compileSerializationSchema(schema, httpStatus)](#compileserializationschema) | ||
- [.serializeInput(data, [schema | httpStatus], [httpStatus])](#serializeinput) | ||
- [.getSerializationFunction(schema | httpStatus)](#getserializationfunctionschema--httpstatus) | ||
- [.compileSerializationSchema(schema, httpStatus)](#compileserializationschemaschema-httpstatus) | ||
- [.serializeInput(data, [schema | httpStatus], [httpStatus])](#serializeinputdata-schema--httpstatus-httpstatus) | ||
- [.serializer(func)](#serializerfunc) | ||
@@ -29,0 +29,0 @@ - [.raw](#raw) |
@@ -38,2 +38,9 @@ <h1 align="center">Fastify</h1> | ||
- `socket` - the underlying connection of the incoming request | ||
- `context` - A Fastify internal object. You should not use it directly or | ||
modify it. It is useful to access one special key: | ||
- `context.config` - The route [`config`](./Routes.md#routes-config) object. | ||
- `routeSchema` - the scheme definition set for the router that is | ||
handling the request | ||
- `routeConfig` - The route [`config`](./Routes.md#routes-config) | ||
object. | ||
- [.getValidationFunction(schema | httpPart)](#getvalidationfunction) - | ||
@@ -52,5 +59,2 @@ Returns a validation function for the specified schema or http part, | ||
function given for that HTTP Status Code. Defaults to `null`. | ||
- `context` - A Fastify internal object. You should not use it directly or | ||
modify it. It is useful to access one special key: | ||
- `context.config` - The route [`config`](./Routes.md#routes-config) object. | ||
@@ -103,2 +107,5 @@ ### Headers | ||
This function has property errors. Errors encountered during the last validation | ||
are assigned to errors | ||
```js | ||
@@ -114,3 +121,4 @@ const validate = request | ||
}) | ||
validate({ foo: 'bar' }) // true | ||
console.log(validate({ foo: 'bar' })) // true | ||
console.log(validate.errors) // null | ||
@@ -121,3 +129,4 @@ // or | ||
.getValidationFunction('body') | ||
validate({ foo: 0.5 }) // false | ||
console.log(validate({ foo: 0.5 })) // false | ||
console.log(validate.errors) // validation errors | ||
``` | ||
@@ -141,2 +150,4 @@ | ||
This function has property errors. Errors encountered during the last validation | ||
are assigned to errors | ||
@@ -154,2 +165,3 @@ ```js | ||
console.log(validate({ foo: 'bar' })) // true | ||
console.log(validate.errors) // null | ||
@@ -168,2 +180,3 @@ // or | ||
console.log(validate({ hello: 'world' })) // false | ||
console.log(validate.errors) // validation errors | ||
``` | ||
@@ -258,2 +271,2 @@ | ||
See [.compileValidationSchema(schema, [httpStatus])](#compileValidationSchema) | ||
for more information on how to compile validation schemas. | ||
for more information on how to compile validation schemas. |
@@ -44,4 +44,4 @@ <h1 align="center">Fastify</h1> | ||
* `body`: validates the body of the request if it is a POST, PUT, or PATCH | ||
method. | ||
* `body`: validates the body of the request if it is a POST, PUT, PATCH, | ||
TRACE, or SEARCH method. | ||
* `querystring` or `query`: validates the querystring. This can be a complete | ||
@@ -48,0 +48,0 @@ JSON Schema object, with the property `type` of `object` and `properties` |
@@ -151,3 +151,3 @@ <h1 align="center">Fastify</h1> | ||
_currently_ is not possible to avoid multiple registrations on routes when | ||
dealing with several scopes, see bellow: | ||
dealing with several scopes, see below: | ||
@@ -222,3 +222,3 @@ ```ts | ||
FastifyInstance, | ||
FastifyLoggerInstance, | ||
FastifyBaseLogger, | ||
RawReplyDefaultExpression, | ||
@@ -234,3 +234,3 @@ RawRequestDefaultExpression, | ||
RawReplyDefaultExpression<RawServerDefault>, | ||
FastifyLoggerInstance, | ||
FastifyBaseLogger, | ||
TypeBoxTypeProvider | ||
@@ -237,0 +237,0 @@ >; |
'use strict' | ||
const VERSION = '4.6.0' | ||
const VERSION = '4.7.0' | ||
@@ -5,0 +5,0 @@ const Avvio = require('avvio') |
'use strict' | ||
const { AsyncResource } = require('async_hooks') | ||
let lru = require('tiny-lru') | ||
// Needed to handle Webpack and faux modules | ||
// See https://github.com/fastify/fastify/issues/2356 | ||
// and https://github.com/fastify/fastify/discussions/2907. | ||
lru = typeof lru === 'function' ? lru : lru.default | ||
const lru = require('tiny-lru').lru | ||
@@ -18,3 +14,4 @@ const secureJson = require('secure-json-parse') | ||
kTestInternals, | ||
kReplyIsError | ||
kReplyIsError, | ||
kRouteContext | ||
} = require('./symbols') | ||
@@ -153,3 +150,7 @@ | ||
if (parser === undefined) { | ||
reply.send(new FST_ERR_CTP_INVALID_MEDIA_TYPE(contentType || undefined)) | ||
if (request.is404) { | ||
handler(request, reply) | ||
} else { | ||
reply.send(new FST_ERR_CTP_INVALID_MEDIA_TYPE(contentType || undefined)) | ||
} | ||
} else if (parser.asString === true || parser.asBuffer === true) { | ||
@@ -159,3 +160,3 @@ rawBody( | ||
reply, | ||
reply.context._parserOptions, | ||
reply[kRouteContext]._parserOptions, | ||
parser, | ||
@@ -191,3 +192,3 @@ done | ||
? NaN | ||
: Number.parseInt(request.headers['content-length'], 10) | ||
: Number(request.headers['content-length']) | ||
@@ -194,0 +195,0 @@ if (contentLength > limit) { |
@@ -15,6 +15,7 @@ 'use strict' | ||
kRequestValidateWeakMap, | ||
kReplySerializeWeakMap | ||
kReplySerializeWeakMap, | ||
kPublicRouteContext | ||
} = require('./symbols.js') | ||
// Objects that holds the context of every request | ||
// Object that holds the context of every request | ||
// Every route holds an instance of this object. | ||
@@ -60,3 +61,6 @@ function Context ({ | ||
this[kReplySerializerDefault] = replySerializer | ||
this.schemaErrorFormatter = schemaErrorFormatter || server[kSchemaErrorFormatter] || defaultSchemaErrorFormatter | ||
this.schemaErrorFormatter = | ||
schemaErrorFormatter || | ||
server[kSchemaErrorFormatter] || | ||
defaultSchemaErrorFormatter | ||
this[kRouteByFastify] = isFastify | ||
@@ -69,5 +73,25 @@ | ||
// Route + Userland configurations for the route | ||
this[kPublicRouteContext] = getPublicRouteContext(this) | ||
this.server = server | ||
} | ||
function getPublicRouteContext (context) { | ||
return Object.create(null, { | ||
schema: { | ||
enumerable: true, | ||
get () { | ||
return context.schema | ||
} | ||
}, | ||
config: { | ||
enumerable: true, | ||
get () { | ||
return context.config | ||
} | ||
} | ||
}) | ||
} | ||
function defaultSchemaErrorFormatter (errors, dataVar) { | ||
@@ -74,0 +98,0 @@ let text = '' |
@@ -6,3 +6,7 @@ 'use strict' | ||
const { | ||
kReplyHeaders, kReplyNextErrorHandler, kReplyIsRunningOnErrorHook, kReplyHasStatusCode | ||
kReplyHeaders, | ||
kReplyNextErrorHandler, | ||
kReplyIsRunningOnErrorHook, | ||
kReplyHasStatusCode, | ||
kRouteContext | ||
} = require('./symbols.js') | ||
@@ -28,3 +32,3 @@ | ||
const context = reply.context | ||
const context = reply[kRouteContext] | ||
if (reply[kReplyNextErrorHandler] === false) { | ||
@@ -95,3 +99,3 @@ fallbackErrorHandler(error, reply, function (reply, payload) { | ||
try { | ||
const serializerFn = getSchemaSerializer(reply.context, statusCode) | ||
const serializerFn = getSchemaSerializer(reply[kRouteContext], statusCode) | ||
payload = (serializerFn === false) | ||
@@ -98,0 +102,0 @@ ? serializeError({ |
@@ -7,3 +7,4 @@ 'use strict' | ||
const { | ||
kReplyIsError | ||
kReplyIsError, | ||
kRouteContext | ||
} = require('./symbols') | ||
@@ -21,4 +22,5 @@ | ||
const headers = request.headers | ||
const context = request[kRouteContext] | ||
if (method === 'GET' || method === 'HEAD' || method === 'SEARCH') { | ||
if (method === 'GET' || method === 'HEAD') { | ||
handler(request, reply) | ||
@@ -30,3 +32,3 @@ return | ||
if (method === 'POST' || method === 'PUT' || method === 'PATCH' || method === 'TRACE') { | ||
if (method === 'POST' || method === 'PUT' || method === 'PATCH' || method === 'TRACE' || method === 'SEARCH') { | ||
if (contentType === undefined) { | ||
@@ -39,6 +41,6 @@ if ( | ||
} else { | ||
reply.context.contentTypeParser.run('', handler, request, reply) | ||
context.contentTypeParser.run('', handler, request, reply) | ||
} | ||
} else { | ||
reply.context.contentTypeParser.run(contentType, handler, request, reply) | ||
context.contentTypeParser.run(contentType, handler, request, reply) | ||
} | ||
@@ -56,3 +58,3 @@ return | ||
) { | ||
reply.context.contentTypeParser.run(contentType, handler, request, reply) | ||
context.contentTypeParser.run(contentType, handler, request, reply) | ||
} else { | ||
@@ -70,5 +72,5 @@ handler(request, reply) | ||
try { | ||
if (reply.context.preValidation !== null) { | ||
if (request[kRouteContext].preValidation !== null) { | ||
hookRunner( | ||
reply.context.preValidation, | ||
request[kRouteContext].preValidation, | ||
hookIterator, | ||
@@ -96,5 +98,5 @@ request, | ||
const result = validateSchema(reply.context, request) | ||
const result = validateSchema(reply[kRouteContext], request) | ||
if (result) { | ||
if (reply.context.attachValidation === false) { | ||
if (reply[kRouteContext].attachValidation === false) { | ||
reply.send(result) | ||
@@ -108,5 +110,5 @@ return | ||
// preHandler hook | ||
if (reply.context.preHandler !== null) { | ||
if (request[kRouteContext].preHandler !== null) { | ||
hookRunner( | ||
reply.context.preHandler, | ||
request[kRouteContext].preHandler, | ||
hookIterator, | ||
@@ -134,3 +136,3 @@ request, | ||
try { | ||
result = reply.context.handler(request, reply) | ||
result = request[kRouteContext].handler(request, reply) | ||
} catch (err) { | ||
@@ -137,0 +139,0 @@ reply[kReplyIsError] = true |
@@ -23,3 +23,4 @@ 'use strict' | ||
kSchemaController, | ||
kOptions | ||
kOptions, | ||
kRouteContext | ||
} = require('./symbols.js') | ||
@@ -67,5 +68,12 @@ const { hookRunner, hookIterator, onSendHookRunner } = require('./hooks') | ||
Object.defineProperties(Reply.prototype, { | ||
[kRouteContext]: { | ||
get () { | ||
return this.request[kRouteContext] | ||
} | ||
}, | ||
// TODO: remove once v5 is done | ||
// Is temporary to avoid constant conflicts between `next` and `main` | ||
context: { | ||
get () { | ||
return this.request.context | ||
return this.request[kRouteContext] | ||
} | ||
@@ -75,3 +83,3 @@ }, | ||
get () { | ||
return this.request.context.server | ||
return this.request[kRouteContext].server | ||
} | ||
@@ -298,3 +306,3 @@ }, | ||
Reply.prototype.code = function (code) { | ||
const intValue = parseInt(code) | ||
const intValue = Number(code) | ||
if (isNaN(intValue) || intValue < 100 || intValue > 599) { | ||
@@ -315,5 +323,5 @@ throw new FST_ERR_BAD_STATUS_CODE(code || String(code)) | ||
if (typeof schemaOrStatus === 'string' || typeof schemaOrStatus === 'number') { | ||
serialize = this.context[kSchemaResponse]?.[schemaOrStatus] | ||
serialize = this[kRouteContext][kSchemaResponse]?.[schemaOrStatus] | ||
} else if (typeof schemaOrStatus === 'object') { | ||
serialize = this.context[kReplySerializeWeakMap]?.get(schemaOrStatus) | ||
serialize = this[kRouteContext][kReplySerializeWeakMap]?.get(schemaOrStatus) | ||
} | ||
@@ -329,7 +337,7 @@ | ||
// Check if serialize function already compiled | ||
if (this.context[kReplySerializeWeakMap]?.has(schema)) { | ||
return this.context[kReplySerializeWeakMap].get(schema) | ||
if (this[kRouteContext][kReplySerializeWeakMap]?.has(schema)) { | ||
return this[kRouteContext][kReplySerializeWeakMap].get(schema) | ||
} | ||
const serializerCompiler = this.context.serializerCompiler || | ||
const serializerCompiler = this[kRouteContext].serializerCompiler || | ||
this.server[kSchemaController].serializerCompiler || | ||
@@ -355,7 +363,7 @@ ( | ||
// encapsulated contexts | ||
if (this.context[kReplySerializeWeakMap] == null) { | ||
this.context[kReplySerializeWeakMap] = new WeakMap() | ||
if (this[kRouteContext][kReplySerializeWeakMap] == null) { | ||
this[kRouteContext][kReplySerializeWeakMap] = new WeakMap() | ||
} | ||
this.context[kReplySerializeWeakMap].set(schema, serializeFn) | ||
this[kRouteContext][kReplySerializeWeakMap].set(schema, serializeFn) | ||
@@ -372,3 +380,3 @@ return serializeFn | ||
if (httpStatus != null) { | ||
serialize = this.context[kSchemaResponse]?.[httpStatus] | ||
serialize = this[kRouteContext][kSchemaResponse]?.[httpStatus] | ||
@@ -378,4 +386,4 @@ if (serialize == null) throw new FST_ERR_MISSING_SERIALIZATION_FN(httpStatus) | ||
// Check if serialize function already compiled | ||
if (this.context[kReplySerializeWeakMap]?.has(schema)) { | ||
serialize = this.context[kReplySerializeWeakMap].get(schema) | ||
if (this[kRouteContext][kReplySerializeWeakMap]?.has(schema)) { | ||
serialize = this[kRouteContext][kReplySerializeWeakMap].get(schema) | ||
} else { | ||
@@ -393,6 +401,6 @@ serialize = this.compileSerializationSchema(schema, httpStatus) | ||
} else { | ||
if (this.context && this.context[kReplySerializerDefault]) { | ||
return this.context[kReplySerializerDefault](payload, this.raw.statusCode) | ||
if (this[kRouteContext] && this[kRouteContext][kReplySerializerDefault]) { | ||
return this[kRouteContext][kReplySerializerDefault](payload, this.raw.statusCode) | ||
} else { | ||
return serialize(this.context, payload, this.raw.statusCode) | ||
return serialize(this[kRouteContext], payload, this.raw.statusCode) | ||
} | ||
@@ -463,5 +471,5 @@ } | ||
function preserializeHook (reply, payload) { | ||
if (reply.context.preSerialization !== null) { | ||
if (reply[kRouteContext].preSerialization !== null) { | ||
onSendHookRunner( | ||
reply.context.preSerialization, | ||
reply[kRouteContext].preSerialization, | ||
reply.request, | ||
@@ -486,6 +494,6 @@ reply, | ||
payload = reply[kReplySerializer](payload) | ||
} else if (reply.context && reply.context[kReplySerializerDefault]) { | ||
payload = reply.context[kReplySerializerDefault](payload, reply.raw.statusCode) | ||
} else if (reply[kRouteContext] && reply[kRouteContext][kReplySerializerDefault]) { | ||
payload = reply[kRouteContext][kReplySerializerDefault](payload, reply.raw.statusCode) | ||
} else { | ||
payload = serialize(reply.context, payload, reply.raw.statusCode) | ||
payload = serialize(reply[kRouteContext], payload, reply.raw.statusCode) | ||
} | ||
@@ -502,9 +510,9 @@ } catch (e) { | ||
function wrapSeralizationError (error, reply) { | ||
error.serialization = reply.context.config | ||
error.serialization = reply[kRouteContext].config | ||
} | ||
function onSendHook (reply, payload) { | ||
if (reply.context.onSend !== null) { | ||
if (reply[kRouteContext].onSend !== null) { | ||
onSendHookRunner( | ||
reply.context.onSend, | ||
reply[kRouteContext].onSend, | ||
reply.request, | ||
@@ -578,3 +586,3 @@ reply, | ||
(req.raw.method !== 'HEAD' && | ||
parseInt(contentLength, 10) !== Buffer.byteLength(payload) | ||
Number(contentLength) !== Buffer.byteLength(payload) | ||
) | ||
@@ -677,6 +685,6 @@ ) { | ||
function onErrorHook (reply, error, cb) { | ||
if (reply.context.onError !== null && !reply[kReplyNextErrorHandler]) { | ||
if (reply[kRouteContext].onError !== null && !reply[kReplyNextErrorHandler]) { | ||
reply[kReplyIsRunningOnErrorHook] = true | ||
onSendHookRunner( | ||
reply.context.onError, | ||
reply[kRouteContext].onError, | ||
reply.request, | ||
@@ -700,3 +708,3 @@ reply, | ||
const ctx = reply.context | ||
const ctx = reply[kRouteContext] | ||
@@ -778,3 +786,3 @@ if (ctx && ctx.onResponse !== null) { | ||
function notFound (reply) { | ||
if (reply.context[kFourOhFourContext] === null) { | ||
if (reply[kRouteContext][kFourOhFourContext] === null) { | ||
reply.log.warn('Trying to send a NotFound error inside a 404 handler. Sending basic 404 response.') | ||
@@ -785,8 +793,8 @@ reply.code(404).send('404 Not Found') | ||
reply.request.context = reply.context[kFourOhFourContext] | ||
reply.request[kRouteContext] = reply[kRouteContext][kFourOhFourContext] | ||
// preHandler hook | ||
if (reply.context.preHandler !== null) { | ||
if (reply[kRouteContext].preHandler !== null) { | ||
hookRunner( | ||
reply.context.preHandler, | ||
reply[kRouteContext].preHandler, | ||
hookIterator, | ||
@@ -793,0 +801,0 @@ reply.request, |
@@ -14,3 +14,5 @@ 'use strict' | ||
kOptions, | ||
kRequestValidateWeakMap | ||
kRequestValidateWeakMap, | ||
kRouteContext, | ||
kPublicRouteContext | ||
} = require('./symbols') | ||
@@ -29,3 +31,3 @@ const { FST_ERR_REQ_INVALID_VALIDATION_INVOCATION } = require('./errors') | ||
this.id = id | ||
this.context = context | ||
this[kRouteContext] = context | ||
this.params = params | ||
@@ -71,3 +73,3 @@ this.raw = req | ||
this.id = id | ||
this.context = context | ||
this[kRouteContext] = context | ||
this.params = params | ||
@@ -145,3 +147,3 @@ this.raw = req | ||
get () { | ||
return this.context.server | ||
return this[kRouteContext].server | ||
} | ||
@@ -159,5 +161,11 @@ }, | ||
}, | ||
context: { | ||
get () { | ||
warning.emit('FSTDEP012') | ||
return this[kRouteContext] | ||
} | ||
}, | ||
routerPath: { | ||
get () { | ||
return this.context.config.url | ||
return this[kRouteContext].config.url | ||
} | ||
@@ -167,8 +175,18 @@ }, | ||
get () { | ||
return this.context.config.method | ||
return this[kRouteContext].config.method | ||
} | ||
}, | ||
routeConfig: { | ||
get () { | ||
return this[kRouteContext][kPublicRouteContext].config | ||
} | ||
}, | ||
routeSchema: { | ||
get () { | ||
return this[kRouteContext][kPublicRouteContext].schema | ||
} | ||
}, | ||
is404: { | ||
get () { | ||
return this.context.config.url === undefined | ||
return this[kRouteContext].config.url === undefined | ||
} | ||
@@ -224,5 +242,5 @@ }, | ||
const symbol = HTTP_PART_SYMBOL_MAP[httpPartOrSchema] | ||
return this.context[symbol] | ||
return this[kRouteContext][symbol] | ||
} else if (typeof httpPartOrSchema === 'object') { | ||
return this.context[kRequestValidateWeakMap]?.get(httpPartOrSchema) | ||
return this[kRouteContext][kRequestValidateWeakMap]?.get(httpPartOrSchema) | ||
} | ||
@@ -235,7 +253,7 @@ } | ||
if (this.context[kRequestValidateWeakMap]?.has(schema)) { | ||
return this.context[kRequestValidateWeakMap].get(schema) | ||
if (this[kRouteContext][kRequestValidateWeakMap]?.has(schema)) { | ||
return this[kRouteContext][kRequestValidateWeakMap].get(schema) | ||
} | ||
const validatorCompiler = this.context.validatorCompiler || | ||
const validatorCompiler = this[kRouteContext].validatorCompiler || | ||
this.server[kSchemaController].validatorCompiler || | ||
@@ -261,7 +279,7 @@ ( | ||
// encapsulated contexts | ||
if (this.context[kRequestValidateWeakMap] == null) { | ||
this.context[kRequestValidateWeakMap] = new WeakMap() | ||
if (this[kRouteContext][kRequestValidateWeakMap] == null) { | ||
this[kRouteContext][kRequestValidateWeakMap] = new WeakMap() | ||
} | ||
this.context[kRequestValidateWeakMap].set(schema, validateFn) | ||
this[kRouteContext][kRequestValidateWeakMap].set(schema, validateFn) | ||
@@ -280,3 +298,3 @@ return validateFn | ||
// Validate using the HTTP Request Part schema | ||
validate = this.context[symbol] | ||
validate = this[kRouteContext][symbol] | ||
} | ||
@@ -293,4 +311,4 @@ | ||
if (validate == null) { | ||
if (this.context[kRequestValidateWeakMap]?.has(schema)) { | ||
validate = this.context[kRequestValidateWeakMap].get(schema) | ||
if (this[kRouteContext][kRequestValidateWeakMap]?.has(schema)) { | ||
validate = this[kRouteContext][kRequestValidateWeakMap].get(schema) | ||
} else { | ||
@@ -297,0 +315,0 @@ // We proceed to compile if there's no validate function yet |
@@ -11,3 +11,2 @@ 'use strict' | ||
const warning = require('./warnings') | ||
const { kRequestAcceptVersion, kRouteByFastify } = require('./symbols') | ||
@@ -41,3 +40,6 @@ const { | ||
kErrorHandler, | ||
kHasBeenDecorated | ||
kHasBeenDecorated, | ||
kRequestAcceptVersion, | ||
kRouteByFastify, | ||
kRouteContext | ||
} = require('./symbols.js') | ||
@@ -160,2 +162,8 @@ const { buildErrorHandler } = require('./error-handler') | ||
const { exposeHeadRoute } = opts | ||
const hasRouteExposeHeadRouteFlag = exposeHeadRoute != null | ||
const shouldExposeHead = hasRouteExposeHeadRouteFlag ? exposeHeadRoute : globalExposeHeadRoutes | ||
// we need to clone a set of initial options for HEAD route | ||
const headOpts = shouldExposeHead && options.method === 'GET' ? { ...options } : null | ||
throwIfAlreadyStarted('Cannot add route when fastify instance is already started!') | ||
@@ -327,3 +335,4 @@ | ||
try { | ||
compileSchemasForValidation(context, opts.validatorCompiler || schemaController.validatorCompiler) | ||
const isCustom = typeof opts?.validatorCompiler === 'function' || schemaController.isCustomValidatorCompiler | ||
compileSchemasForValidation(context, opts.validatorCompiler || schemaController.validatorCompiler, isCustom) | ||
} catch (error) { | ||
@@ -349,9 +358,6 @@ throw new FST_ERR_SCH_VALIDATION_BUILD(opts.method, url, error.message) | ||
// we must place it after the `this.after` | ||
const { exposeHeadRoute } = opts | ||
const hasRouteExposeHeadRouteFlag = exposeHeadRoute != null | ||
const shouldExposeHead = hasRouteExposeHeadRouteFlag ? exposeHeadRoute : globalExposeHeadRoutes | ||
if (shouldExposeHead && options.method === 'GET' && !hasHEADHandler) { | ||
const onSendHandlers = parseHeadOnSendHandlers(opts.onSend) | ||
prepareRoute.call(this, { method: 'HEAD', url: path, options: { ...opts, onSend: onSendHandlers }, isFastify: true }) | ||
const onSendHandlers = parseHeadOnSendHandlers(headOpts.onSend) | ||
prepareRoute.call(this, { method: 'HEAD', url: path, options: { ...headOpts, onSend: onSendHandlers }, isFastify: true }) | ||
} else if (hasHEADHandler && exposeHeadRoute) { | ||
@@ -498,4 +504,4 @@ warning.emit('FSTDEP007') | ||
if (reply.context.preParsing !== null) { | ||
preParsingHookRunner(reply.context.preParsing, request, reply, handleRequest) | ||
if (request[kRouteContext].preParsing !== null) { | ||
preParsingHookRunner(request[kRouteContext].preParsing, request, reply, handleRequest) | ||
} else { | ||
@@ -502,0 +508,0 @@ handleRequest(null, request, reply) |
@@ -28,3 +28,5 @@ 'use strict' | ||
bucket: (opts && opts.bucket) || buildSchemas, | ||
compilersFactory | ||
compilersFactory, | ||
isCustomValidatorCompiler: typeof opts?.compilersFactory?.buildValidator === 'function', | ||
isCustomSerializerCompiler: typeof opts?.compilersFactory?.buildValidator === 'function' | ||
} | ||
@@ -41,2 +43,4 @@ | ||
this.compilersFactory = this.opts.compilersFactory | ||
this.isCustomValidatorCompiler = this.opts.isCustomValidatorCompiler || false | ||
this.isCustomSerializerCompiler = this.opts.isCustomSerializerCompiler || false | ||
@@ -70,2 +74,3 @@ if (parent) { | ||
this.validatorCompiler = validatorCompiler | ||
this.isCustomValidatorCompiler = true | ||
} | ||
@@ -75,2 +80,3 @@ | ||
this.serializerCompiler = serializerCompiler | ||
this.isCustomSerializerCompiler = true | ||
} | ||
@@ -77,0 +83,0 @@ |
@@ -334,4 +334,4 @@ 'use strict' | ||
function normalizePort (firstArg) { | ||
const port = parseInt(firstArg, 10) | ||
return port >= 0 && !Number.isNaN(port) ? port : 0 | ||
const port = Number(firstArg) | ||
return port >= 0 && !Number.isNaN(port) && Number.isInteger(port) ? port : 0 | ||
} | ||
@@ -338,0 +338,0 @@ |
@@ -17,2 +17,4 @@ 'use strict' | ||
kPluginNameChain: Symbol('fastify.pluginNameChain'), | ||
kRouteContext: Symbol('fastify.context'), | ||
kPublicRouteContext: Symbol('fastify.routeOptions'), | ||
// Schema | ||
@@ -19,0 +21,0 @@ kSchemaController: Symbol('fastify.schemaController'), |
@@ -35,3 +35,3 @@ 'use strict' | ||
function compileSchemasForValidation (context, compile) { | ||
function compileSchemasForValidation (context, compile, isCustom) { | ||
const { schema } = context | ||
@@ -45,4 +45,5 @@ if (!schema) { | ||
const headers = schema.headers | ||
if (headers && Object.getPrototypeOf(headers) !== Object.prototype) { | ||
// do not mess with non-literals, e.g. Joi schemas | ||
// the or part is used for backward compatibility | ||
if (headers && (isCustom || Object.getPrototypeOf(headers) !== Object.prototype)) { | ||
// do not mess with schema when custom validator applied, e.g. Joi, Typebox | ||
context[headersSchema] = compile({ schema: headers, method, url, httpPart: 'headers' }) | ||
@@ -49,0 +50,0 @@ } else if (headers) { |
@@ -24,2 +24,4 @@ 'use strict' | ||
warning.create('FastifyDeprecation', 'FSTDEP012', 'Request#context property access is deprecated. Please use "Request#routeConfig" or "Request#routeSchema" instead for accessing Route settings. The "Request#context" will be removed in `fastify@5`.') | ||
module.exports = warning |
{ | ||
"name": "fastify", | ||
"version": "4.6.0", | ||
"version": "4.7.0", | ||
"description": "Fast and low overhead web framework, for Node.js", | ||
@@ -129,7 +129,7 @@ "main": "fastify.js", | ||
"@fastify/pre-commit": "^2.0.2", | ||
"@sinclair/typebox": "^0.24.9", | ||
"@sinclair/typebox": "^0.24.41", | ||
"@sinonjs/fake-timers": "^9.1.2", | ||
"@types/node": "^18.0.0", | ||
"@typescript-eslint/eslint-plugin": "^5.27.0", | ||
"@typescript-eslint/parser": "^5.27.0", | ||
"@types/node": "^18.7.18", | ||
"@typescript-eslint/eslint-plugin": "^5.37.0", | ||
"@typescript-eslint/parser": "^5.37.0", | ||
"ajv": "^8.11.0", | ||
@@ -141,11 +141,11 @@ "ajv-errors": "^3.0.0", | ||
"branch-comparer": "^1.1.0", | ||
"eslint": "^8.16.0", | ||
"eslint-config-standard": "^17.0.0-1", | ||
"eslint": "^8.23.1", | ||
"eslint-config-standard": "^17.0.0", | ||
"eslint-import-resolver-node": "^0.3.6", | ||
"eslint-plugin-import": "^2.26.0", | ||
"eslint-plugin-n": "^15.2.0", | ||
"eslint-plugin-promise": "^6.0.0", | ||
"eslint-plugin-n": "^15.2.5", | ||
"eslint-plugin-promise": "^6.0.1", | ||
"fast-json-body": "^1.1.0", | ||
"fast-json-stringify": "^5.0.0", | ||
"fastify-plugin": "^4.0.0", | ||
"fast-json-stringify": "^5.3.0", | ||
"fastify-plugin": "^4.2.1", | ||
"fluent-json-schema": "^3.1.0", | ||
@@ -156,6 +156,6 @@ "form-data": "^4.0.0", | ||
"joi": "^17.6.0", | ||
"json-schema-to-ts": "^2.5.3", | ||
"json-schema-to-ts": "^2.5.5", | ||
"JSONStream": "^1.3.5", | ||
"license-checker": "^25.0.1", | ||
"markdownlint-cli2": "^0.5.0", | ||
"markdownlint-cli2": "^0.5.1", | ||
"proxyquire": "^2.1.3", | ||
@@ -168,7 +168,7 @@ "pump": "^3.0.0", | ||
"split2": "^4.1.0", | ||
"standard": "^17.0.0-2", | ||
"tap": "^16.2.0", | ||
"tsd": "^0.23.0", | ||
"typescript": "^4.7.2", | ||
"undici": "^5.4.0", | ||
"standard": "^17.0.0", | ||
"tap": "^16.3.0", | ||
"tsd": "^0.24.1", | ||
"typescript": "^4.8.3", | ||
"undici": "^5.10.0", | ||
"vary": "^1.1.2", | ||
@@ -178,16 +178,16 @@ "yup": "^0.32.11" | ||
"dependencies": { | ||
"@fastify/ajv-compiler": "^3.1.1", | ||
"@fastify/ajv-compiler": "^3.3.1", | ||
"@fastify/error": "^3.0.0", | ||
"@fastify/fast-json-stringify-compiler": "^4.0.0", | ||
"@fastify/fast-json-stringify-compiler": "^4.1.0", | ||
"abstract-logging": "^2.0.1", | ||
"avvio": "^8.1.3", | ||
"find-my-way": "^7.0.0", | ||
"light-my-request": "^5.5.1", | ||
"pino": "^8.0.0", | ||
"avvio": "^8.2.0", | ||
"find-my-way": "^7.2.0", | ||
"light-my-request": "^5.6.1", | ||
"pino": "^8.5.0", | ||
"process-warning": "^2.0.0", | ||
"proxy-addr": "^2.0.7", | ||
"rfdc": "^1.3.0", | ||
"secure-json-parse": "^2.4.0", | ||
"secure-json-parse": "^2.5.0", | ||
"semver": "^7.3.7", | ||
"tiny-lru": "^8.0.2" | ||
"tiny-lru": "^9.0.2" | ||
}, | ||
@@ -194,0 +194,0 @@ "standard": { |
@@ -9,2 +9,3 @@ 'use strict' | ||
const split = require('split2') | ||
const FormData = require('form-data') | ||
const Fastify = require('..') | ||
@@ -22,3 +23,3 @@ | ||
test('default 404', t => { | ||
t.plan(4) | ||
t.plan(5) | ||
@@ -79,2 +80,19 @@ const test = t.test | ||
}) | ||
test('using post method and multipart/formdata', t => { | ||
t.plan(3) | ||
const form = FormData() | ||
form.append('test-field', 'just some field') | ||
sget({ | ||
method: 'POST', | ||
url: getUrl(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') | ||
}) | ||
}) | ||
}) | ||
@@ -81,0 +99,0 @@ }) |
@@ -5,2 +5,3 @@ 'use strict' | ||
const test = t.test | ||
const { kRouteContext } = require('../lib/symbols') | ||
const Fastify = require('..') | ||
@@ -17,3 +18,3 @@ | ||
function handler (req, reply) { | ||
reply.send(reply.context.config) | ||
reply.send(reply[kRouteContext].config) | ||
} | ||
@@ -20,0 +21,0 @@ |
'use strict' | ||
const http = require('http') | ||
const test = require('tap').test | ||
const { kRouteContext } = require('../lib/symbols') | ||
const fastify = require('../') | ||
function getUrl (app) { | ||
const { address, port } = app.server.address() | ||
if (address === '::1') { | ||
return `http://[${address}]:${port}` | ||
} else { | ||
return `http://${address}:${port}` | ||
} | ||
} | ||
test('handlers receive correct `this` context', (t) => { | ||
test('handlers receive correct `this` context', async (t) => { | ||
t.plan(4) | ||
@@ -35,13 +25,9 @@ | ||
instance.listen({ port: 0 }, (err) => { | ||
instance.server.unref() | ||
if (err) t.threw(err) | ||
t.ok(instance.foo) | ||
t.equal(instance.foo, 'foo') | ||
await instance.inject('/') | ||
http.get(getUrl(instance), () => {}).on('error', t.threw) | ||
}) | ||
t.ok(instance.foo) | ||
t.equal(instance.foo, 'foo') | ||
}) | ||
test('handlers have access to the internal context', (t) => { | ||
test('handlers have access to the internal context', async (t) => { | ||
t.plan(5) | ||
@@ -51,15 +37,11 @@ | ||
instance.get('/', { config: { foo: 'bar' } }, function (req, reply) { | ||
t.ok(reply.context) | ||
t.ok(reply.context.config) | ||
t.type(reply.context.config, Object) | ||
t.ok(reply.context.config.foo) | ||
t.equal(reply.context.config.foo, 'bar') | ||
t.ok(reply[kRouteContext]) | ||
t.ok(reply[kRouteContext].config) | ||
t.type(reply[kRouteContext].config, Object) | ||
t.ok(reply[kRouteContext].config.foo) | ||
t.equal(reply[kRouteContext].config.foo, 'bar') | ||
reply.send() | ||
}) | ||
instance.listen({ port: 0 }, (err) => { | ||
instance.server.unref() | ||
if (err) t.threw(err) | ||
http.get(getUrl(instance), () => {}).on('error', t.threw) | ||
}) | ||
await instance.inject('/') | ||
}) |
@@ -7,3 +7,3 @@ 'use strict' | ||
const { Readable } = require('stream') | ||
const { kTestInternals } = require('../../lib/symbols') | ||
const { kTestInternals, kRouteContext } = require('../../lib/symbols') | ||
const Request = require('../../lib/request') | ||
@@ -54,3 +54,3 @@ const Reply = require('../../lib/reply') | ||
reply, | ||
reply.context._parserOptions, | ||
reply[kRouteContext]._parserOptions, | ||
parser, | ||
@@ -108,3 +108,3 @@ done | ||
reply, | ||
reply.context._parserOptions, | ||
reply[kRouteContext]._parserOptions, | ||
parser, | ||
@@ -111,0 +111,0 @@ done |
@@ -8,2 +8,3 @@ 'use strict' | ||
const Reply = require('../../lib/reply') | ||
const { kRouteContext } = require('../../lib/symbols') | ||
const buildSchema = require('../../lib/validation').compileSchemasForValidation | ||
@@ -73,3 +74,3 @@ const sget = require('simple-get').concat | ||
body: { hello: 'world' }, | ||
context | ||
[kRouteContext]: context | ||
} | ||
@@ -101,3 +102,3 @@ internals.handler(request, new Reply(res, request)) | ||
buildSchema(context, schemaValidator) | ||
internals.handler({}, new Reply(res, { context })) | ||
internals.handler({ [kRouteContext]: context }, new Reply(res, { [kRouteContext]: context })) | ||
}) | ||
@@ -127,3 +128,3 @@ | ||
buildSchema(context, schemaValidator) | ||
internals.handler({}, new Reply(res, { context })) | ||
internals.handler({ [kRouteContext]: context }, new Reply(res, { [kRouteContext]: context })) | ||
}) | ||
@@ -130,0 +131,0 @@ |
'use strict' | ||
const { test } = require('tap') | ||
const { kReplySerializeWeakMap } = require('../../lib/symbols') | ||
const { kReplySerializeWeakMap, kRouteContext } = require('../../lib/symbols') | ||
const Fastify = require('../../fastify') | ||
@@ -175,5 +175,5 @@ | ||
t.equal(reply.context[kReplySerializeWeakMap], null) | ||
t.equal(reply[kRouteContext][kReplySerializeWeakMap], null) | ||
t.equal(reply.compileSerializationSchema(getDefaultSchema())(input), JSON.stringify(input)) | ||
t.type(reply.context[kReplySerializeWeakMap], WeakMap) | ||
t.type(reply[kRouteContext][kReplySerializeWeakMap], WeakMap) | ||
t.equal(reply.compileSerializationSchema(getDefaultSchema())(input), JSON.stringify(input)) | ||
@@ -235,3 +235,3 @@ | ||
if (parseInt(id) === 1) { | ||
if (Number(id) === 1) { | ||
const serialize4xx = reply.getSerializationFunction('4xx') | ||
@@ -313,3 +313,3 @@ const serialize201 = reply.getSerializationFunction(201) | ||
if (parseInt(id) === 1) { | ||
if (Number(id) === 1) { | ||
const serialize = reply.compileSerializationSchema(schemaObj) | ||
@@ -358,5 +358,5 @@ | ||
t.notOk(reply.getSerializationFunction(getDefaultSchema())) | ||
t.equal(reply.context[kReplySerializeWeakMap], null) | ||
t.equal(reply[kRouteContext][kReplySerializeWeakMap], null) | ||
t.notOk(reply.getSerializationFunction('200')) | ||
t.equal(reply.context[kReplySerializeWeakMap], null) | ||
t.equal(reply[kRouteContext][kReplySerializeWeakMap], null) | ||
@@ -575,5 +575,5 @@ reply.send({ hello: 'world' }) | ||
const input = { hello: 'world' } | ||
t.equal(reply.context[kReplySerializeWeakMap], null) | ||
t.equal(reply[kRouteContext][kReplySerializeWeakMap], null) | ||
t.equal(reply.serializeInput(input, getDefaultSchema()), JSON.stringify(input)) | ||
t.type(reply.context[kReplySerializeWeakMap], WeakMap) | ||
t.type(reply[kRouteContext][kReplySerializeWeakMap], WeakMap) | ||
@@ -580,0 +580,0 @@ reply.send({ hello: 'world' }) |
@@ -15,3 +15,4 @@ 'use strict' | ||
kReplyIsError, | ||
kReplySerializerDefault | ||
kReplySerializerDefault, | ||
kRouteContext | ||
} = require('../../lib/symbols') | ||
@@ -38,3 +39,3 @@ const fs = require('fs') | ||
const context = {} | ||
const request = { context } | ||
const request = { [kRouteContext]: context } | ||
const reply = new Reply(response, request) | ||
@@ -52,3 +53,3 @@ t.equal(typeof reply, 'object') | ||
t.same(reply.raw, response) | ||
t.equal(reply.context, context) | ||
t.equal(reply[kRouteContext], context) | ||
t.equal(reply.request, request) | ||
@@ -82,3 +83,3 @@ }) | ||
const reply = new Reply(response, { context: { onSend: null } }, log) | ||
const reply = new Reply(response, { [kRouteContext]: { onSend: null } }, log) | ||
reply.send(payload) | ||
@@ -100,3 +101,3 @@ payload.destroy(new Error('stream error')) | ||
} | ||
const reply = new Reply(response, { context: { onSend: [] } }) | ||
const reply = new Reply(response, { [kRouteContext]: { onSend: [] } }) | ||
t.throws(() => { | ||
@@ -119,3 +120,3 @@ const obj = {} | ||
} | ||
const reply = new Reply(response, { context: { onSend: [] } }) | ||
const reply = new Reply(response, { [kRouteContext]: { onSend: [] } }) | ||
t.equal(reply.send('hello'), reply) | ||
@@ -161,3 +162,3 @@ }) | ||
const context = {} | ||
const reply = new Reply(response, { context }) | ||
const reply = new Reply(response, { [kRouteContext]: context }) | ||
t.equal(reply.serialize({ foo: 'bar' }), '{"foo":"bar"}') | ||
@@ -171,3 +172,3 @@ }) | ||
const context = {} | ||
const reply = new Reply(response, { context }) | ||
const reply = new Reply(response, { [kRouteContext]: context }) | ||
reply.serializer((x) => (customSerializerCalled = true) && JSON.stringify(x)) | ||
@@ -183,3 +184,3 @@ t.equal(reply.serialize({ foo: 'bar' }), '{"foo":"bar"}') | ||
const context = { [kReplySerializerDefault]: (x) => (customSerializerCalled = true) && JSON.stringify(x) } | ||
const reply = new Reply(response, { context }) | ||
const reply = new Reply(response, { [kRouteContext]: context }) | ||
t.equal(reply.serialize({ foo: 'bar' }), '{"foo":"bar"}') | ||
@@ -186,0 +187,0 @@ t.equal(customSerializerCalled, true, 'custom serializer not called') |
@@ -5,3 +5,3 @@ 'use strict' | ||
const Ajv = require('ajv') | ||
const { kRequestValidateWeakMap } = require('../../lib/symbols') | ||
const { kRequestValidateWeakMap, kRouteContext } = require('../../lib/symbols') | ||
const Fastify = require('../../fastify') | ||
@@ -40,3 +40,3 @@ | ||
test('#compileValidationSchema', subtest => { | ||
subtest.plan(5) | ||
subtest.plan(7) | ||
@@ -64,2 +64,45 @@ subtest.test('Should return a function - Route without schema', async t => { | ||
subtest.test('Validate function errors property should be null after validation when input is valid', async t => { | ||
const fastify = Fastify() | ||
t.plan(3) | ||
fastify.get('/', (req, reply) => { | ||
const validate = req.compileValidationSchema(defaultSchema) | ||
t.ok(validate({ hello: 'world' })) | ||
t.ok(Object.prototype.hasOwnProperty.call(validate, 'errors')) | ||
t.equal(validate.errors, null) | ||
reply.send({ hello: 'world' }) | ||
}) | ||
await fastify.inject({ | ||
path: '/', | ||
method: 'GET' | ||
}) | ||
}) | ||
subtest.test('Validate function errors property should be an array of errors after validation when input is valid', async t => { | ||
const fastify = Fastify() | ||
t.plan(4) | ||
fastify.get('/', (req, reply) => { | ||
const validate = req.compileValidationSchema(defaultSchema) | ||
t.notOk(validate({ world: 'foo' })) | ||
t.ok(Object.prototype.hasOwnProperty.call(validate, 'errors')) | ||
t.ok(Array.isArray(validate.errors)) | ||
t.ok(validate.errors.length > 0) | ||
reply.send({ hello: 'world' }) | ||
}) | ||
await fastify.inject({ | ||
path: '/', | ||
method: 'GET' | ||
}) | ||
}) | ||
subtest.test( | ||
@@ -194,7 +237,7 @@ 'Should reuse the validate fn across multiple invocations - Route without schema', | ||
fastify.get('/', (req, reply) => { | ||
t.equal(req.context[kRequestValidateWeakMap], null) | ||
t.equal(req[kRouteContext][kRequestValidateWeakMap], null) | ||
t.type(req.compileValidationSchema(defaultSchema), Function) | ||
t.type(req.context[kRequestValidateWeakMap], WeakMap) | ||
t.type(req[kRouteContext][kRequestValidateWeakMap], WeakMap) | ||
t.type(req.compileValidationSchema(Object.assign({}, defaultSchema)), Function) | ||
t.type(req.context[kRequestValidateWeakMap], WeakMap) | ||
t.type(req[kRouteContext][kRequestValidateWeakMap], WeakMap) | ||
@@ -213,3 +256,3 @@ reply.send({ hello: 'world' }) | ||
test('#getValidationFunction', subtest => { | ||
subtest.plan(4) | ||
subtest.plan(6) | ||
@@ -236,2 +279,47 @@ subtest.test('Should return a validation function', async t => { | ||
subtest.test('Validate function errors property should be null after validation when input is valid', async t => { | ||
const fastify = Fastify() | ||
t.plan(3) | ||
fastify.get('/', (req, reply) => { | ||
req.compileValidationSchema(defaultSchema) | ||
const validate = req.getValidationFunction(defaultSchema) | ||
t.ok(validate({ hello: 'world' })) | ||
t.ok(Object.prototype.hasOwnProperty.call(validate, 'errors')) | ||
t.equal(validate.errors, null) | ||
reply.send({ hello: 'world' }) | ||
}) | ||
await fastify.inject({ | ||
path: '/', | ||
method: 'GET' | ||
}) | ||
}) | ||
subtest.test('Validate function errors property should be an array of errors after validation when input is valid', async t => { | ||
const fastify = Fastify() | ||
t.plan(4) | ||
fastify.get('/', (req, reply) => { | ||
req.compileValidationSchema(defaultSchema) | ||
const validate = req.getValidationFunction(defaultSchema) | ||
t.notOk(validate({ world: 'foo' })) | ||
t.ok(Object.prototype.hasOwnProperty.call(validate, 'errors')) | ||
t.ok(Array.isArray(validate.errors)) | ||
t.ok(validate.errors.length > 0) | ||
reply.send({ hello: 'world' }) | ||
}) | ||
await fastify.inject({ | ||
path: '/', | ||
method: 'GET' | ||
}) | ||
}) | ||
subtest.test('Should return undefined if no schema compiled', async t => { | ||
@@ -345,3 +433,3 @@ const fastify = Fastify() | ||
t.equal(req.context[kRequestValidateWeakMap], null) | ||
t.equal(req[kRouteContext][kRequestValidateWeakMap], null) | ||
reply.send({ hello: 'world' }) | ||
@@ -646,5 +734,5 @@ }) | ||
fastify.get('/', (req, reply) => { | ||
t.equal(req.context[kRequestValidateWeakMap], null) | ||
t.equal(req[kRouteContext][kRequestValidateWeakMap], null) | ||
t.equal(req.validateInput({ hello: 'world' }, defaultSchema), true) | ||
t.type(req.context[kRequestValidateWeakMap], WeakMap) | ||
t.type(req[kRouteContext][kRequestValidateWeakMap], WeakMap) | ||
@@ -651,0 +739,0 @@ reply.send({ hello: 'world' }) |
@@ -6,2 +6,8 @@ 'use strict' | ||
const Request = require('../../lib/request') | ||
const Context = require('../../lib/context') | ||
const { | ||
kPublicRouteContext, | ||
kReply, | ||
kRequest | ||
} = require('../../lib/symbols') | ||
@@ -20,4 +26,24 @@ process.removeAllListeners('warning') | ||
} | ||
const context = new Context({ | ||
schema: { | ||
body: { | ||
type: 'object', | ||
required: ['hello'], | ||
properties: { | ||
hello: { type: 'string' } | ||
} | ||
} | ||
}, | ||
config: { | ||
some: 'config', | ||
url: req.url, | ||
method: req.method | ||
}, | ||
server: { | ||
[kReply]: {}, | ||
[kRequest]: Request | ||
} | ||
}) | ||
req.connection = req.socket | ||
const request = new Request('id', 'params', req, 'query', 'log') | ||
const request = new Request('id', 'params', req, 'query', 'log', context) | ||
t.type(request, Request) | ||
@@ -41,2 +67,6 @@ t.type(request.validateInput, Function) | ||
t.equal(request.protocol, 'http') | ||
t.equal(request.routerPath, context.config.url) | ||
t.equal(request.routerMethod, context.config.method) | ||
t.equal(request.routeConfig, context[kPublicRouteContext].config) | ||
t.equal(request.routeSchema, context[kPublicRouteContext].schema) | ||
@@ -83,3 +113,3 @@ // This will be removed, it's deprecated | ||
test('Request with trust proxy', t => { | ||
t.plan(18) | ||
t.plan(22) | ||
const headers = { | ||
@@ -95,5 +125,25 @@ 'x-forwarded-for': '2.2.2.2, 1.1.1.1', | ||
} | ||
const context = new Context({ | ||
schema: { | ||
body: { | ||
type: 'object', | ||
required: ['hello'], | ||
properties: { | ||
hello: { type: 'string' } | ||
} | ||
} | ||
}, | ||
config: { | ||
some: 'config', | ||
url: req.url, | ||
method: req.method | ||
}, | ||
server: { | ||
[kReply]: {}, | ||
[kRequest]: Request | ||
} | ||
}) | ||
const TpRequest = Request.buildRequest(Request, true) | ||
const request = new TpRequest('id', 'params', req, 'query', 'log') | ||
const request = new TpRequest('id', 'params', req, 'query', 'log', context) | ||
t.type(request, TpRequest) | ||
@@ -117,2 +167,6 @@ t.equal(request.id, 'id') | ||
t.type(request.compileValidationSchema, Function) | ||
t.equal(request.routerPath, context.config.url) | ||
t.equal(request.routerMethod, context.config.method) | ||
t.equal(request.routeConfig, context[kPublicRouteContext].config) | ||
t.equal(request.routeSchema, context[kPublicRouteContext].schema) | ||
}) | ||
@@ -119,0 +173,0 @@ |
@@ -271,2 +271,17 @@ 'use strict' | ||
test('build schema - headers are not lowercased in case of custom validator provided', t => { | ||
t.plan(1) | ||
class Headers {} | ||
const opts = { | ||
schema: { | ||
headers: new Headers() | ||
} | ||
} | ||
validation.compileSchemasForValidation(opts, ({ schema, method, url, httpPart }) => { | ||
t.type(schema, Headers) | ||
return () => {} | ||
}, true) | ||
}) | ||
test('build schema - uppercased headers are not included', t => { | ||
@@ -273,0 +288,0 @@ t.plan(1) |
@@ -888,3 +888,3 @@ 'use strict' | ||
test('pluginTimeout - named function', { only: true }, t => { | ||
test('pluginTimeout - named function', t => { | ||
t.plan(5) | ||
@@ -891,0 +891,0 @@ const fastify = Fastify({ |
@@ -1467,1 +1467,30 @@ 'use strict' | ||
}) | ||
test('exposeHeadRoute should not reuse the same route option', async t => { | ||
t.plan(2) | ||
const fastify = Fastify() | ||
// we update the onRequest hook in onRoute hook | ||
// if we reuse the same route option | ||
// that means we will append another function inside the array | ||
fastify.addHook('onRoute', function (routeOption) { | ||
if (Array.isArray(routeOption.onRequest)) { | ||
routeOption.onRequest.push(() => {}) | ||
} else { | ||
routeOption.onRequest = [() => {}] | ||
} | ||
}) | ||
fastify.addHook('onRoute', function (routeOption) { | ||
t.equal(routeOption.onRequest.length, 1) | ||
}) | ||
fastify.route({ | ||
method: 'GET', | ||
path: '/more-coffee', | ||
async handler () { | ||
return 'hello world' | ||
} | ||
}) | ||
}) |
'use strict' | ||
const test = require('tap').test | ||
const sget = require('simple-get') | ||
const Fastify = require('../') | ||
const { FST_ERR_BAD_URL } = require('../lib/errors') | ||
function getUrl (app) { | ||
const { address, port } = app.server.address() | ||
if (address === '::1') { | ||
return `http://[${address}]:${port}` | ||
} else { | ||
return `http://${address}:${port}` | ||
} | ||
} | ||
test('Should honor ignoreTrailingSlash option', t => { | ||
test('Should honor ignoreTrailingSlash option', async t => { | ||
t.plan(4) | ||
@@ -27,23 +17,12 @@ const fastify = Fastify({ | ||
fastify.listen({ port: 0 }, (err) => { | ||
t.teardown(() => { fastify.close() }) | ||
if (err) t.threw(err) | ||
let res = await fastify.inject('/test') | ||
t.equal(res.statusCode, 200) | ||
t.equal(res.payload.toString(), 'test') | ||
const baseUrl = getUrl(fastify) | ||
sget.concat(baseUrl + '/test', (err, res, data) => { | ||
if (err) t.threw(err) | ||
t.equal(res.statusCode, 200) | ||
t.equal(data.toString(), 'test') | ||
}) | ||
sget.concat(baseUrl + '/test/', (err, res, data) => { | ||
if (err) t.threw(err) | ||
t.equal(res.statusCode, 200) | ||
t.equal(data.toString(), 'test') | ||
}) | ||
}) | ||
res = await fastify.inject('/test/') | ||
t.equal(res.statusCode, 200) | ||
t.equal(res.payload.toString(), 'test') | ||
}) | ||
test('Should honor ignoreDuplicateSlashes option', t => { | ||
test('Should honor ignoreDuplicateSlashes option', async t => { | ||
t.plan(4) | ||
@@ -58,23 +37,12 @@ const fastify = Fastify({ | ||
fastify.listen({ port: 0 }, (err) => { | ||
t.teardown(() => { fastify.close() }) | ||
if (err) t.threw(err) | ||
let res = await fastify.inject('/test/test/test') | ||
t.equal(res.statusCode, 200) | ||
t.equal(res.payload.toString(), 'test') | ||
const baseUrl = getUrl(fastify) | ||
sget.concat(baseUrl + '/test/test/test', (err, res, data) => { | ||
if (err) t.threw(err) | ||
t.equal(res.statusCode, 200) | ||
t.equal(data.toString(), 'test') | ||
}) | ||
sget.concat(baseUrl + '/test//test///test', (err, res, data) => { | ||
if (err) t.threw(err) | ||
t.equal(res.statusCode, 200) | ||
t.equal(data.toString(), 'test') | ||
}) | ||
}) | ||
res = await fastify.inject('/test//test///test') | ||
t.equal(res.statusCode, 200) | ||
t.equal(res.payload.toString(), 'test') | ||
}) | ||
test('Should honor ignoreTrailingSlash and ignoreDuplicateSlashes options', t => { | ||
test('Should honor ignoreTrailingSlash and ignoreDuplicateSlashes options', async t => { | ||
t.plan(4) | ||
@@ -90,20 +58,9 @@ const fastify = Fastify({ | ||
fastify.listen({ port: 0 }, (err) => { | ||
t.teardown(() => { fastify.close() }) | ||
if (err) t.threw(err) | ||
let res = await fastify.inject('/test/test/test/') | ||
t.equal(res.statusCode, 200) | ||
t.equal(res.payload.toString(), 'test') | ||
const baseUrl = getUrl(fastify) | ||
sget.concat(baseUrl + '/test/test/test/', (err, res, data) => { | ||
if (err) t.threw(err) | ||
t.equal(res.statusCode, 200) | ||
t.equal(data.toString(), 'test') | ||
}) | ||
sget.concat(baseUrl + '/test//test///test//', (err, res, data) => { | ||
if (err) t.threw(err) | ||
t.equal(res.statusCode, 200) | ||
t.equal(data.toString(), 'test') | ||
}) | ||
}) | ||
res = await fastify.inject('/test//test///test//') | ||
t.equal(res.statusCode, 200) | ||
t.equal(res.payload.toString(), 'test') | ||
}) | ||
@@ -137,8 +94,18 @@ | ||
test('Should expose router options via getters on request and reply', t => { | ||
t.plan(7) | ||
t.plan(10) | ||
const fastify = Fastify() | ||
const expectedSchema = { | ||
params: { | ||
id: { type: 'integer' } | ||
} | ||
} | ||
fastify.get('/test/:id', (req, reply) => { | ||
fastify.get('/test/:id', { | ||
schema: expectedSchema | ||
}, (req, reply) => { | ||
t.equal(reply.context.config.url, '/test/:id') | ||
t.equal(reply.context.config.method, 'GET') | ||
t.equal(req.routeConfig.url, '/test/:id') | ||
t.equal(req.routeConfig.method, 'GET') | ||
t.same(req.routeSchema, expectedSchema) | ||
t.equal(req.routerPath, '/test/:id') | ||
@@ -145,0 +112,0 @@ t.equal(req.routerMethod, 'GET') |
@@ -1782,1 +1782,26 @@ 'use strict' | ||
}) | ||
test('setSchemaController: custom validator instance should not mutate headers schema', async t => { | ||
t.plan(2) | ||
class Headers {} | ||
const fastify = Fastify() | ||
fastify.setSchemaController({ | ||
compilersFactory: { | ||
buildValidator: function () { | ||
return ({ schema, method, url, httpPart }) => { | ||
t.type(schema, Headers) | ||
return () => {} | ||
} | ||
} | ||
} | ||
}) | ||
fastify.get('/', { | ||
schema: { | ||
headers: new Headers() | ||
} | ||
}, () => {}) | ||
await fastify.ready() | ||
}) |
@@ -1020,1 +1020,20 @@ 'use strict' | ||
}) | ||
test('Custom validator compiler should not mutate schema', async t => { | ||
t.plan(2) | ||
class Headers {} | ||
const fastify = Fastify() | ||
fastify.setValidatorCompiler(({ schema, method, url, httpPart }) => { | ||
t.type(schema, Headers) | ||
return () => {} | ||
}) | ||
fastify.get('/', { | ||
schema: { | ||
headers: new Headers() | ||
} | ||
}, () => {}) | ||
await fastify.ready() | ||
}) |
'use strict' | ||
const t = require('tap') | ||
const sget = require('simple-get').concat | ||
const test = t.test | ||
@@ -8,10 +9,8 @@ const fastify = require('..')() | ||
const schema = { | ||
schema: { | ||
response: { | ||
'2xx': { | ||
type: 'object', | ||
properties: { | ||
hello: { | ||
type: 'string' | ||
} | ||
response: { | ||
'2xx': { | ||
type: 'object', | ||
properties: { | ||
hello: { | ||
type: 'string' | ||
} | ||
@@ -24,9 +23,7 @@ } | ||
const querySchema = { | ||
schema: { | ||
querystring: { | ||
type: 'object', | ||
properties: { | ||
hello: { | ||
type: 'integer' | ||
} | ||
querystring: { | ||
type: 'object', | ||
properties: { | ||
hello: { | ||
type: 'integer' | ||
} | ||
@@ -38,12 +35,10 @@ } | ||
const paramsSchema = { | ||
schema: { | ||
params: { | ||
type: 'object', | ||
properties: { | ||
foo: { | ||
type: 'string' | ||
}, | ||
test: { | ||
type: 'integer' | ||
} | ||
params: { | ||
type: 'object', | ||
properties: { | ||
foo: { | ||
type: 'string' | ||
}, | ||
test: { | ||
type: 'integer' | ||
} | ||
@@ -54,3 +49,17 @@ } | ||
test('shorthand - search', t => { | ||
const bodySchema = { | ||
body: { | ||
type: 'object', | ||
properties: { | ||
foo: { | ||
type: 'string' | ||
}, | ||
test: { | ||
type: 'integer' | ||
} | ||
} | ||
} | ||
} | ||
test('search', t => { | ||
t.plan(1) | ||
@@ -72,3 +81,3 @@ try { | ||
test('shorthand - search params', t => { | ||
test('search, params schema', t => { | ||
t.plan(1) | ||
@@ -79,3 +88,3 @@ try { | ||
url: '/params/:foo/:test', | ||
paramsSchema, | ||
schema: paramsSchema, | ||
handler: function (request, reply) { | ||
@@ -91,3 +100,3 @@ reply.code(200).send(request.params) | ||
test('shorthand - get, querystring schema', t => { | ||
test('search, querystring schema', t => { | ||
t.plan(1) | ||
@@ -98,3 +107,3 @@ try { | ||
url: '/query', | ||
querySchema, | ||
schema: querySchema, | ||
handler: function (request, reply) { | ||
@@ -109,1 +118,131 @@ reply.code(200).send(request.query) | ||
}) | ||
test('search, body schema', t => { | ||
t.plan(1) | ||
try { | ||
fastify.route({ | ||
method: 'SEARCH', | ||
url: '/body', | ||
schema: bodySchema, | ||
handler: function (request, reply) { | ||
reply.code(200).send(request.body) | ||
} | ||
}) | ||
t.pass() | ||
} catch (e) { | ||
t.fail() | ||
} | ||
}) | ||
fastify.listen({ port: 0 }, err => { | ||
t.error(err) | ||
t.teardown(() => { fastify.close() }) | ||
const url = `http://localhost:${fastify.server.address().port}` | ||
test('request - search', t => { | ||
t.plan(4) | ||
sget({ | ||
method: 'SEARCH', | ||
url | ||
}, (err, response, body) => { | ||
t.error(err) | ||
t.equal(response.statusCode, 200) | ||
t.equal(response.headers['content-length'], '' + body.length) | ||
t.same(JSON.parse(body), { hello: 'world' }) | ||
}) | ||
}) | ||
test('request search params schema', t => { | ||
t.plan(4) | ||
sget({ | ||
method: 'SEARCH', | ||
url: `${url}/params/world/123` | ||
}, (err, response, body) => { | ||
t.error(err) | ||
t.equal(response.statusCode, 200) | ||
t.equal(response.headers['content-length'], '' + body.length) | ||
t.same(JSON.parse(body), { foo: 'world', test: 123 }) | ||
}) | ||
}) | ||
test('request search params schema error', t => { | ||
t.plan(3) | ||
sget({ | ||
method: 'SEARCH', | ||
url: `${url}/params/world/string` | ||
}, (err, response, body) => { | ||
t.error(err) | ||
t.equal(response.statusCode, 400) | ||
t.same(JSON.parse(body), { | ||
error: 'Bad Request', | ||
message: 'params/test must be integer', | ||
statusCode: 400 | ||
}) | ||
}) | ||
}) | ||
test('request search querystring schema', t => { | ||
t.plan(4) | ||
sget({ | ||
method: 'SEARCH', | ||
url: `${url}/query?hello=123` | ||
}, (err, response, body) => { | ||
t.error(err) | ||
t.equal(response.statusCode, 200) | ||
t.equal(response.headers['content-length'], '' + body.length) | ||
t.same(JSON.parse(body), { hello: 123 }) | ||
}) | ||
}) | ||
test('request search querystring schema error', t => { | ||
t.plan(3) | ||
sget({ | ||
method: 'SEARCH', | ||
url: `${url}/query?hello=world` | ||
}, (err, response, body) => { | ||
t.error(err) | ||
t.equal(response.statusCode, 400) | ||
t.same(JSON.parse(body), { | ||
error: 'Bad Request', | ||
message: 'querystring/hello must be integer', | ||
statusCode: 400 | ||
}) | ||
}) | ||
}) | ||
test('request search body schema', t => { | ||
t.plan(4) | ||
const replyBody = { foo: 'bar', test: 5 } | ||
sget({ | ||
method: 'SEARCH', | ||
url: `${url}/body`, | ||
body: JSON.stringify(replyBody), | ||
headers: { 'content-type': 'application/json' } | ||
}, (err, response, body) => { | ||
t.error(err) | ||
t.equal(response.statusCode, 200) | ||
t.equal(response.headers['content-length'], '' + body.length) | ||
t.same(JSON.parse(body), replyBody) | ||
}) | ||
}) | ||
test('request search body schema error', t => { | ||
t.plan(4) | ||
sget({ | ||
method: 'SEARCH', | ||
url: `${url}/body`, | ||
body: JSON.stringify({ foo: 'bar', test: 'test' }), | ||
headers: { 'content-type': 'application/json' } | ||
}, (err, response, body) => { | ||
t.error(err) | ||
t.equal(response.statusCode, 400) | ||
t.equal(response.headers['content-length'], '' + body.length) | ||
t.same(JSON.parse(body), { | ||
error: 'Bad Request', | ||
message: 'body/test must be integer', | ||
statusCode: 400 | ||
}) | ||
}) | ||
}) | ||
}) |
@@ -0,1 +1,2 @@ | ||
import { ErrorObject } from '@fastify/ajv-compiler' | ||
import { FastifyBaseLogger } from './logger' | ||
@@ -17,2 +18,7 @@ import { ContextConfigDefault, RawServerBase, RawServerDefault, RawRequestDefaultExpression, RequestBodyDefault, RequestQuerystringDefault, RequestParamsDefault, RequestHeadersDefault } from './utils' | ||
export interface ValidationFunction { | ||
(input: any): boolean | ||
errors?: null | ErrorObject[]; | ||
} | ||
/** | ||
@@ -65,5 +71,5 @@ * FastifyRequest is an instance of the standard http or http2 request objects. | ||
getValidationFunction(httpPart: HTTPRequestPart): (input: any) => boolean | ||
getValidationFunction(schema: {[key: string]: any}): (input: any) => boolean | ||
compileValidationSchema(schema: {[key: string]: any}, httpPart?: HTTPRequestPart): (input: any) => boolean | ||
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 | ||
@@ -70,0 +76,0 @@ validateInput(input: any, httpPart?: HTTPRequestPart): boolean |
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
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
1931608
272
46386
46
+ Addedtiny-lru@9.0.3(transitive)
- Removedtiny-lru@8.0.2(transitive)
Updated@fastify/ajv-compiler@^3.3.1
Updatedavvio@^8.2.0
Updatedfind-my-way@^7.2.0
Updatedlight-my-request@^5.6.1
Updatedpino@^8.5.0
Updatedsecure-json-parse@^2.5.0
Updatedtiny-lru@^9.0.2