fastify 4.14.0 → 4.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -304,6 +304,8 @@ listed in alphabetical order.
304
304
  <https://twitter.com/ayoubelkh>, <https://www.npmjs.com/~ayoubelk>
305
305
  * [__Denis Fäcke__](https://github.com/SerayaEryn),
306
306
  <https://twitter.com/serayaeryn>, <https://www.npmjs.com/~serayaeryn>
307
+ * [__Carlos Fuentes__](https://github.com/metcoder95),
308
+ <https://twitter.com/metcoder95>, <https://www.npmjs.com/~metcoder95>
307
309
  * [__Rafael Gonzaga__](https://github.com/rafaelgss),
308
310
  <https://twitter.com/_rafaelgss>, <https://www.npmjs.com/~rafaelgss>
309
311
  * [__Vincent Le Goff__](https://github.com/zekth)
@@ -327,6 +329,8 @@ listed in alphabetical order.
327
329
  <https://twitter.com/delvedor>, <https://www.npmjs.com/~delvedor>
328
330
  * [__Ayoub El Khattabi__](https://github.com/AyoubElk),
329
331
  <https://twitter.com/ayoubelkh>, <https://www.npmjs.com/~ayoubelk>
332
+ * [__Carlos Fuentes__](https://github.com/metcoder95),
333
+ <https://twitter.com/metcoder95>, <https://www.npmjs.com/~metcoder95>
330
334
  * [__Vincent Le Goff__](https://github.com/zekth)
331
335
  * [__Salman Mitha__](https://github.com/salmanm),
332
336
  <https://www.npmjs.com/~salmanm>
@@ -338,7 +342,7 @@ listed in alphabetical order.
338
342
  * [__Rafael Gonzaga__](https://github.com/rafaelgss),
339
343
  <https://twitter.com/_rafaelgss>, <https://www.npmjs.com/~rafaelgss>
340
344
  * [__Simone Busoli__](https://github.com/simoneb),
341
- <https://twitter.com/simonebu>, <https://www.npmjs.com/~simoneb>
345
+ <https://twitter.com/simonebu>, <https://www.npmjs.com/~simoneb>
342
346
 
343
347
  ### Great Contributors
344
348
  Great contributors on a specific area in the Fastify ecosystem will be invited
@@ -281,6 +281,12 @@ A callback for a hook timed out
281
281
 
282
282
  The logger accepts either a `'stream'` or a `'file'` as the destination.
283
283
 
284
+ #### FST_ERR_LOG_INVALID_LOGGER
285
+ <a id="FST_ERR_LOG_INVALID_LOGGER"></a>
286
+
287
+ The logger should have all these methods: `'info'`, `'error'`,
288
+ `'debug'`, `'fatal'`, `'warn'`, `'trace'`, `'child'`.
289
+
284
290
  #### FST_ERR_REP_INVALID_PAYLOAD_TYPE
285
291
  <a id="FST_ERR_REP_INVALID_PAYLOAD_TYPE"></a>
286
292
 
@@ -284,7 +284,7 @@ fastify.addHook('onRequestAbort', async (request, reply) => {
284
284
  })
285
285
  ```
286
286
  The `onRequestAbort` hook is executed when a client closes the connection before
287
- the entire request has been received. Therefore, you will not be able to send
287
+ the entire request has been processed. Therefore, you will not be able to send
288
288
  data to the client.
289
289
 
290
290
  **Notice:** client abort detection is not completely reliable. See: [`Detecting-When-Clients-Abort.md`](../Guides/Detecting-When-Clients-Abort.md)
@@ -738,7 +738,8 @@ Fastify provides default error handlers for the most common use cases. It is
738
738
  possible to override one or more of those handlers with custom code using this
739
739
  option.
740
740
 
741
- *Note: Only `FST_ERR_BAD_URL` is implemented at the moment.*
741
+ *Note: Only `FST_ERR_BAD_URL` and `FST_ERR_ASYNC_CONSTRAINT` are implemented at
742
+ the moment.*
742
743
 
743
744
  ```js
744
745
  const fastify = require('fastify')({
@@ -1544,35 +1545,61 @@ a custom constraint strategy with the same name.
1544
1545
  #### printRoutes
1545
1546
  <a id="print-routes"></a>
1546
1547
 
1547
- `fastify.printRoutes()`: Prints the representation of the internal radix tree
1548
- used by the router, useful for debugging. Alternatively, `fastify.printRoutes({
1549
- commonPrefix: false })` can be used to print the flattened routes tree.
1548
+ `fastify.printRoutes()`: Fastify router builds a tree of routes for each HTTP
1549
+ method. If you call the prettyPrint without specifying an HTTP method, it will
1550
+ merge all the trees into one and print it. The merged tree doesn't represent the
1551
+ internal router structure. **Don't use it for debugging.**
1550
1552
 
1551
1553
  *Remember to call it inside or after a `ready` call.*
1552
1554
 
1553
1555
  ```js
1554
1556
  fastify.get('/test', () => {})
1555
1557
  fastify.get('/test/hello', () => {})
1556
- fastify.get('/hello/world', () => {})
1557
- fastify.get('/helicopter', () => {})
1558
+ fastify.get('/testing', () => {})
1559
+ fastify.get('/testing/:param', () => {})
1560
+ fastify.put('/update', () => {})
1558
1561
 
1559
1562
  fastify.ready(() => {
1560
1563
  console.log(fastify.printRoutes())
1561
1564
  // └── /
1562
1565
  // ├── test (GET)
1563
- // │ └── /hello (GET)
1564
- // └── hel
1565
- // ├── lo/world (GET)
1566
- // └── licopter (GET)
1566
+ // │ ├── /hello (GET)
1567
+ // └── ing (GET)
1568
+ // │ └── /
1569
+ //└── :param (GET)
1570
+ // └── update (PUT)
1571
+ })
1572
+ ```
1567
1573
 
1568
- console.log(fastify.printRoutes({ commonPrefix: false }))
1569
- // └── / (-)
1570
- // ├── test (GET)
1571
- // │ └── /hello (GET)
1572
- // ├── hello/world (GET)
1573
- // └── helicopter (GET)
1574
+ If you want to print the internal router tree, you should specify the `method`
1575
+ param. Printed tree will represent the internal router structure.
1576
+ **You can use it for debugging.**
1574
1577
 
1575
- })
1578
+ ```js
1579
+ console.log(fastify.printRoutes({ method: 'GET' }))
1580
+ // └── /
1581
+ // └── test (GET)
1582
+ // ├── /hello (GET)
1583
+ // └── ing (GET)
1584
+ // └── /
1585
+ // └── :param (GET)
1586
+
1587
+ console.log(fastify.printRoutes({ method: 'PUT' }))
1588
+ // └── /
1589
+ // └── update (PUT)
1590
+ ```
1591
+
1592
+ `fastify.printRoutes({ commonPrefix: false })` will print compressed trees. This
1593
+ might useful when you have a large number of routes with common prefixes.
1594
+ It doesn't represent the internal router structure. **Don't use it for debugging.**
1595
+
1596
+ ```js
1597
+ console.log(fastify.printRoutes({ commonPrefix: false }))
1598
+ // ├── /test (GET)
1599
+ // │ ├── /hello (GET)
1600
+ // │ └── ing (GET)
1601
+ // │ └── /:param (GET)
1602
+ // └── /update (PUT)
1576
1603
  ```
1577
1604
 
1578
1605
  `fastify.printRoutes({ includeMeta: (true | []) })` will display properties from
@@ -1582,26 +1609,51 @@ A shorthand option, `fastify.printRoutes({ includeHooks: true })` will include
1582
1609
  all [hooks](./Hooks.md).
1583
1610
 
1584
1611
  ```js
1585
- console.log(fastify.printRoutes({ includeHooks: true, includeMeta: ['metaProperty'] }))
1612
+ fastify.get('/test', () => {})
1613
+ fastify.get('/test/hello', () => {})
1614
+
1615
+ const onTimeout = () => {}
1616
+
1617
+ fastify.addHook('onRequest', () => {})
1618
+ fastify.addHook('onTimeout', onTimeout)
1619
+
1620
+ console.log(fastify.printRoutes({ includeHooks: true, includeMeta: ['errorHandler'] }))
1586
1621
  // └── /
1587
- // ├── test (GET)
1588
- //• (onRequest) ["anonymous()","namedFunction()"]
1589
- //• (metaProperty) "value"
1590
- // │ └── /hello (GET)
1591
- // └── hel
1592
- // ├── lo/world (GET)
1593
- // • (onTimeout) ["anonymous()"]
1594
- // └── licopter (GET)
1622
+ // └── test (GET)
1623
+ // • (onTimeout) ["onTimeout()"]
1624
+ // • (onRequest) ["anonymous()"]
1625
+ // (errorHandler) "defaultErrorHandler()"
1626
+ // test (HEAD)
1627
+ // (onTimeout) ["onTimeout()"]
1628
+ // • (onRequest) ["anonymous()"]
1629
+ // (onSend) ["headRouteOnSendHandler()"]
1630
+ // • (errorHandler) "defaultErrorHandler()"
1631
+ // └── /hello (GET)
1632
+ // • (onTimeout) ["onTimeout()"]
1633
+ // • (onRequest) ["anonymous()"]
1634
+ // • (errorHandler) "defaultErrorHandler()"
1635
+ // /hello (HEAD)
1636
+ // • (onTimeout) ["onTimeout()"]
1637
+ // • (onRequest) ["anonymous()"]
1638
+ // • (onSend) ["headRouteOnSendHandler()"]
1639
+ // • (errorHandler) "defaultErrorHandler()"
1595
1640
 
1596
1641
  console.log(fastify.printRoutes({ includeHooks: true }))
1597
1642
  // └── /
1598
- // ├── test (GET)
1599
- //• (onRequest) ["anonymous()","namedFunction()"]
1600
- // │ └── /hello (GET)
1601
- // └── hel
1602
- // ├── lo/world (GET)
1603
- // • (onTimeout) ["anonymous()"]
1604
- // └── licopter (GET)
1643
+ // └── test (GET)
1644
+ // • (onTimeout) ["onTimeout()"]
1645
+ // (onRequest) ["anonymous()"]
1646
+ // test (HEAD)
1647
+ // (onTimeout) ["onTimeout()"]
1648
+ // • (onRequest) ["anonymous()"]
1649
+ // (onSend) ["headRouteOnSendHandler()"]
1650
+ // └── /hello (GET)
1651
+ // • (onTimeout) ["onTimeout()"]
1652
+ // • (onRequest) ["anonymous()"]
1653
+ // /hello (HEAD)
1654
+ // • (onTimeout) ["onTimeout()"]
1655
+ // • (onRequest) ["anonymous()"]
1656
+ // • (onSend) ["headRouteOnSendHandler()"]
1605
1657
  ```
1606
1658
 
1607
1659
  #### printPlugins
package/fastify.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const VERSION = '4.14.0'
3
+ const VERSION = '4.15.0'
4
4
 
5
5
  const Avvio = require('avvio')
6
6
  const http = require('http')
@@ -396,10 +396,18 @@ function ParserListItem (contentType) {
396
396
  // we pre-calculate all the needed information
397
397
  // before content-type comparsion
398
398
  const parsed = safeParseContentType(contentType)
399
- this.type = parsed.type
399
+ this.isEssence = contentType.indexOf(';') === -1
400
+ // we should not allow empty string for parser list item
401
+ // because it would become a match-all handler
402
+ if (this.isEssence === false && parsed.type === '') {
403
+ // handle semicolon or empty string
404
+ const tmp = contentType.split(';')[0]
405
+ this.type = tmp === '' ? contentType : tmp
406
+ } else {
407
+ this.type = parsed.type
408
+ }
400
409
  this.parameters = parsed.parameters
401
410
  this.parameterKeys = Object.keys(parsed.parameters)
402
- this.isEssence = contentType.indexOf(';') === -1
403
411
  }
404
412
 
405
413
  // used in ContentTypeParser.remove
package/lib/context.js CHANGED
@@ -11,8 +11,8 @@ const {
11
11
  kLogLevel,
12
12
  kContentTypeParser,
13
13
  kRouteByFastify,
14
- kRequestValidateWeakMap,
15
- kReplySerializeWeakMap,
14
+ kRequestCacheValidateFns,
15
+ kReplyCacheSerializeFns,
16
16
  kPublicRouteContext
17
17
  } = require('./symbols.js')
18
18
 
@@ -68,8 +68,8 @@ function Context ({
68
68
  defaultSchemaErrorFormatter
69
69
  this[kRouteByFastify] = isFastify
70
70
 
71
- this[kRequestValidateWeakMap] = null
72
- this[kReplySerializeWeakMap] = null
71
+ this[kRequestCacheValidateFns] = null
72
+ this[kReplyCacheSerializeFns] = null
73
73
  this.validatorCompiler = validatorCompiler || null
74
74
  this.serializerCompiler = serializerCompiler || null
75
75
 
package/lib/errors.js CHANGED
@@ -177,6 +177,11 @@ const codes = {
177
177
  'Cannot specify both logger.stream and logger.file options'
178
178
  ),
179
179
 
180
+ FST_ERR_LOG_INVALID_LOGGER: createError(
181
+ 'FST_ERR_LOG_INVALID_LOGGER',
182
+ "Invalid logger object provided. The logger instance should have these functions(s): '%s'."
183
+ ),
184
+
180
185
  /**
181
186
  * reply
182
187
  */
package/lib/logger.js CHANGED
@@ -9,17 +9,17 @@
9
9
  const nullLogger = require('abstract-logging')
10
10
  const pino = require('pino')
11
11
  const { serializersSym } = pino.symbols
12
- const { FST_ERR_LOG_INVALID_DESTINATION } = require('./errors')
12
+ const {
13
+ FST_ERR_LOG_INVALID_DESTINATION,
14
+ FST_ERR_LOG_INVALID_LOGGER
15
+ } = require('./errors')
13
16
 
14
- function createPinoLogger (opts, stream) {
15
- stream = stream || opts.stream
16
- delete opts.stream
17
-
18
- if (stream && opts.file) {
17
+ function createPinoLogger (opts) {
18
+ if (opts.stream && opts.file) {
19
19
  throw new FST_ERR_LOG_INVALID_DESTINATION()
20
20
  } else if (opts.file) {
21
21
  // we do not have stream
22
- stream = pino.destination(opts.file)
22
+ opts.stream = pino.destination(opts.file)
23
23
  delete opts.file
24
24
  }
25
25
 
@@ -39,7 +39,7 @@ function createPinoLogger (opts, stream) {
39
39
  opts.logger = prevLogger
40
40
  opts.genReqId = prevGenReqId
41
41
  } else {
42
- logger = pino(opts, stream)
42
+ logger = pino(opts, opts.stream)
43
43
  }
44
44
 
45
45
  return logger
@@ -70,50 +70,60 @@ function now () {
70
70
  }
71
71
 
72
72
  function createLogger (options) {
73
- if (isValidLogger(options.logger)) {
73
+ if (!options.logger) {
74
+ const logger = nullLogger
75
+ logger.child = () => logger
76
+ return { logger, hasLogger: false }
77
+ }
78
+
79
+ if (validateLogger(options.logger)) {
74
80
  const logger = createPinoLogger({
75
81
  logger: options.logger,
76
82
  serializers: Object.assign({}, serializers, options.logger.serializers)
77
83
  })
78
84
  return { logger, hasLogger: true }
79
- } else if (!options.logger) {
80
- const logger = nullLogger
81
- logger.child = () => logger
82
- return { logger, hasLogger: false }
83
- } else {
84
- const localLoggerOptions = {}
85
- if (Object.prototype.toString.call(options.logger) === '[object Object]') {
86
- Reflect.ownKeys(options.logger).forEach(prop => {
87
- Object.defineProperty(localLoggerOptions, prop, {
88
- value: options.logger[prop],
89
- writable: true,
90
- enumerable: true,
91
- configurable: true
92
- })
93
- })
94
- }
95
- localLoggerOptions.level = localLoggerOptions.level || 'info'
96
- localLoggerOptions.serializers = Object.assign({}, serializers, localLoggerOptions.serializers)
97
- options.logger = localLoggerOptions
98
- const logger = createPinoLogger(options.logger)
99
- return { logger, hasLogger: true }
100
85
  }
101
- }
102
86
 
103
- function isValidLogger (logger) {
104
- if (!logger) {
105
- return false
87
+ const localLoggerOptions = {}
88
+ if (Object.prototype.toString.call(options.logger) === '[object Object]') {
89
+ Reflect.ownKeys(options.logger).forEach(prop => {
90
+ Object.defineProperty(localLoggerOptions, prop, {
91
+ value: options.logger[prop],
92
+ writable: true,
93
+ enumerable: true,
94
+ configurable: true
95
+ })
96
+ })
106
97
  }
98
+ localLoggerOptions.level = localLoggerOptions.level || 'info'
99
+ localLoggerOptions.serializers = Object.assign({}, serializers, localLoggerOptions.serializers)
100
+ options.logger = localLoggerOptions
101
+ const logger = createPinoLogger(options.logger)
102
+ return { logger, hasLogger: true }
103
+ }
107
104
 
108
- let result = true
105
+ /**
106
+ * Determines if a provided logger object meets the requirements
107
+ * of a Fastify compatible logger.
108
+ *
109
+ * @param {object} logger Object to validate.
110
+ *
111
+ * @returns {boolean} `true` when the logger meets the requirements.
112
+ *
113
+ * @throws {FST_ERR_LOG_INVALID_LOGGER} When the logger object is
114
+ * missing required methods.
115
+ */
116
+ function validateLogger (logger) {
109
117
  const methods = ['info', 'error', 'debug', 'fatal', 'warn', 'trace', 'child']
110
- for (let i = 0; i < methods.length; i += 1) {
111
- if (!logger[methods[i]] || typeof logger[methods[i]] !== 'function') {
112
- result = false
113
- break
114
- }
118
+ const missingMethods = methods.filter(method => !logger[method] || typeof logger[method] !== 'function')
119
+
120
+ if (!missingMethods.length) {
121
+ return true
122
+ } else if (missingMethods.length === methods.length) {
123
+ return false
124
+ } else {
125
+ throw FST_ERR_LOG_INVALID_LOGGER(missingMethods.join(','))
115
126
  }
116
- return result
117
127
  }
118
128
 
119
129
  module.exports = {
package/lib/reply.js CHANGED
@@ -18,7 +18,7 @@ const {
18
18
  kReplyNextErrorHandler,
19
19
  kDisableRequestLogging,
20
20
  kSchemaResponse,
21
- kReplySerializeWeakMap,
21
+ kReplyCacheSerializeFns,
22
22
  kSchemaController,
23
23
  kOptions,
24
24
  kRouteContext
@@ -323,7 +323,7 @@ Reply.prototype.getSerializationFunction = function (schemaOrStatus, contentType
323
323
  serialize = this[kRouteContext][kSchemaResponse]?.[schemaOrStatus]
324
324
  }
325
325
  } else if (typeof schemaOrStatus === 'object') {
326
- serialize = this[kRouteContext][kReplySerializeWeakMap]?.get(schemaOrStatus)
326
+ serialize = this[kRouteContext][kReplyCacheSerializeFns]?.get(schemaOrStatus)
327
327
  }
328
328
 
329
329
  return serialize
@@ -334,8 +334,8 @@ Reply.prototype.compileSerializationSchema = function (schema, httpStatus = null
334
334
  const { method, url } = request
335
335
 
336
336
  // Check if serialize function already compiled
337
- if (this[kRouteContext][kReplySerializeWeakMap]?.has(schema)) {
338
- return this[kRouteContext][kReplySerializeWeakMap].get(schema)
337
+ if (this[kRouteContext][kReplyCacheSerializeFns]?.has(schema)) {
338
+ return this[kRouteContext][kReplyCacheSerializeFns].get(schema)
339
339
  }
340
340
 
341
341
  const serializerCompiler = this[kRouteContext].serializerCompiler ||
@@ -360,11 +360,11 @@ Reply.prototype.compileSerializationSchema = function (schema, httpStatus = null
360
360
  // if it is not used
361
361
  // TODO: Explore a central cache for all the schemas shared across
362
362
  // encapsulated contexts
363
- if (this[kRouteContext][kReplySerializeWeakMap] == null) {
364
- this[kRouteContext][kReplySerializeWeakMap] = new WeakMap()
363
+ if (this[kRouteContext][kReplyCacheSerializeFns] == null) {
364
+ this[kRouteContext][kReplyCacheSerializeFns] = new WeakMap()
365
365
  }
366
366
 
367
- this[kRouteContext][kReplySerializeWeakMap].set(schema, serializeFn)
367
+ this[kRouteContext][kReplyCacheSerializeFns].set(schema, serializeFn)
368
368
 
369
369
  return serializeFn
370
370
  }
@@ -393,8 +393,8 @@ Reply.prototype.serializeInput = function (input, schema, httpStatus, contentTyp
393
393
  }
394
394
  } else {
395
395
  // Check if serialize function already compiled
396
- if (this[kRouteContext][kReplySerializeWeakMap]?.has(schema)) {
397
- serialize = this[kRouteContext][kReplySerializeWeakMap].get(schema)
396
+ if (this[kRouteContext][kReplyCacheSerializeFns]?.has(schema)) {
397
+ serialize = this[kRouteContext][kReplyCacheSerializeFns].get(schema)
398
398
  } else {
399
399
  serialize = this.compileSerializationSchema(schema, httpStatus, contentType)
400
400
  }
package/lib/request.js CHANGED
@@ -11,7 +11,7 @@ const {
11
11
  kSchemaQuerystring,
12
12
  kSchemaController,
13
13
  kOptions,
14
- kRequestValidateWeakMap,
14
+ kRequestCacheValidateFns,
15
15
  kRouteContext,
16
16
  kPublicRouteContext
17
17
  } = require('./symbols')
@@ -254,7 +254,7 @@ Object.defineProperties(Request.prototype, {
254
254
  const symbol = HTTP_PART_SYMBOL_MAP[httpPartOrSchema]
255
255
  return this[kRouteContext][symbol]
256
256
  } else if (typeof httpPartOrSchema === 'object') {
257
- return this[kRouteContext][kRequestValidateWeakMap]?.get(httpPartOrSchema)
257
+ return this[kRouteContext][kRequestCacheValidateFns]?.get(httpPartOrSchema)
258
258
  }
259
259
  }
260
260
  },
@@ -262,8 +262,8 @@ Object.defineProperties(Request.prototype, {
262
262
  value: function (schema, httpPart = null) {
263
263
  const { method, url } = this
264
264
 
265
- if (this[kRouteContext][kRequestValidateWeakMap]?.has(schema)) {
266
- return this[kRouteContext][kRequestValidateWeakMap].get(schema)
265
+ if (this[kRouteContext][kRequestCacheValidateFns]?.has(schema)) {
266
+ return this[kRouteContext][kRequestCacheValidateFns].get(schema)
267
267
  }
268
268
 
269
269
  const validatorCompiler = this[kRouteContext].validatorCompiler ||
@@ -287,11 +287,11 @@ Object.defineProperties(Request.prototype, {
287
287
  // if it is not used
288
288
  // TODO: Explore a central cache for all the schemas shared across
289
289
  // encapsulated contexts
290
- if (this[kRouteContext][kRequestValidateWeakMap] == null) {
291
- this[kRouteContext][kRequestValidateWeakMap] = new WeakMap()
290
+ if (this[kRouteContext][kRequestCacheValidateFns] == null) {
291
+ this[kRouteContext][kRequestCacheValidateFns] = new WeakMap()
292
292
  }
293
293
 
294
- this[kRouteContext][kRequestValidateWeakMap].set(schema, validateFn)
294
+ this[kRouteContext][kRequestCacheValidateFns].set(schema, validateFn)
295
295
 
296
296
  return validateFn
297
297
  }
@@ -317,8 +317,8 @@ Object.defineProperties(Request.prototype, {
317
317
  }
318
318
 
319
319
  if (validate == null) {
320
- if (this[kRouteContext][kRequestValidateWeakMap]?.has(schema)) {
321
- validate = this[kRouteContext][kRequestValidateWeakMap].get(schema)
320
+ if (this[kRouteContext][kRequestCacheValidateFns]?.has(schema)) {
321
+ validate = this[kRouteContext][kRequestCacheValidateFns].get(schema)
322
322
  } else {
323
323
  // We proceed to compile if there's no validate function yet
324
324
  validate = this.compileValidationSchema(schema, httpPart)
package/lib/symbols.js CHANGED
@@ -27,10 +27,9 @@ const keys = {
27
27
  kSchemaVisited: Symbol('fastify.schemas.visited'),
28
28
  // Request
29
29
  kRequest: Symbol('fastify.Request'),
30
- kRequestValidateFns: Symbol('fastify.request.cache.validateFns'),
31
30
  kRequestPayloadStream: Symbol('fastify.RequestPayloadStream'),
32
31
  kRequestAcceptVersion: Symbol('fastify.RequestAcceptVersion'),
33
- kRequestValidateWeakMap: Symbol('fastify.request.cache.validators'),
32
+ kRequestCacheValidateFns: Symbol('fastify.request.cache.validateFns'),
34
33
  // 404
35
34
  kFourOhFour: Symbol('fastify.404'),
36
35
  kCanSetNotFoundHandler: Symbol('fastify.canSetNotFoundHandler'),
@@ -51,7 +50,7 @@ const keys = {
51
50
  kReplyErrorHandlerCalled: Symbol('fastify.reply.errorHandlerCalled'),
52
51
  kReplyIsRunningOnErrorHook: Symbol('fastify.reply.isRunningOnErrorHook'),
53
52
  kReplySerializerDefault: Symbol('fastify.replySerializerDefault'),
54
- kReplySerializeWeakMap: Symbol('fastify.reply.cache.serializeFns'),
53
+ kReplyCacheSerializeFns: Symbol('fastify.reply.cache.serializeFns'),
55
54
  // This symbol is only meant to be used for fastify tests and should not be used for any other purpose
56
55
  kTestInternals: Symbol('fastify.testInternals'),
57
56
  kErrorHandler: Symbol('fastify.errorHandler'),
package/lib/validation.js CHANGED
@@ -80,18 +80,26 @@ function compileSchemasForValidation (context, compile, isCustom) {
80
80
  })
81
81
  }
82
82
  context[headersSchema] = compile({ schema: headersSchemaLowerCase, method, url, httpPart: 'headers' })
83
+ } else if (Object.hasOwnProperty.call(schema, 'headers')) {
84
+ throw new Error('headers schema is undefined')
83
85
  }
84
86
 
85
87
  if (schema.body) {
86
88
  context[bodySchema] = compile({ schema: schema.body, method, url, httpPart: 'body' })
89
+ } else if (Object.hasOwnProperty.call(schema, 'body')) {
90
+ throw new Error('body schema is undefined')
87
91
  }
88
92
 
89
93
  if (schema.querystring) {
90
94
  context[querystringSchema] = compile({ schema: schema.querystring, method, url, httpPart: 'querystring' })
95
+ } else if (Object.hasOwnProperty.call(schema, 'querystring')) {
96
+ throw new Error('querystring schema is undefined')
91
97
  }
92
98
 
93
99
  if (schema.params) {
94
100
  context[paramsSchema] = compile({ schema: schema.params, method, url, httpPart: 'params' })
101
+ } else if (Object.hasOwnProperty.call(schema, 'params')) {
102
+ throw new Error('params schema is undefined')
95
103
  }
96
104
  }
97
105
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fastify",
3
- "version": "4.14.0",
3
+ "version": "4.15.0",
4
4
  "description": "Fast and low overhead web framework, for Node.js",
5
5
  "main": "fastify.js",
6
6
  "type": "commonjs",
@@ -8,6 +8,7 @@
8
8
  "scripts": {
9
9
  "bench": "branchcmp -r 2 -g -s \"npm run benchmark\"",
10
10
  "benchmark": "npx concurrently -k -s first \"node ./examples/benchmark/simple.js\" \"npx autocannon -c 100 -d 30 -p 10 localhost:3000/\"",
11
+ "build:validation": "node build/build-error-serializer.js && node build/build-validation.js",
11
12
  "coverage": "npm run unit -- --cov --coverage-report=html",
12
13
  "coverage:ci": "npm run unit -- --cov --coverage-report=html --no-browser --no-check-coverage -R terse",
13
14
  "coverage:ci-check-coverage": "nyc check-coverage --branches 100 --functions 100 --lines 100 --statements 100",
@@ -17,10 +18,11 @@
17
18
  "lint:markdown": "markdownlint-cli2",
18
19
  "lint:standard": "standard | snazzy",
19
20
  "lint:typescript": "eslint -c types/.eslintrc.json types/**/*.d.ts test/types/**/*.test-d.ts",
20
- "prepublishOnly": "PREPUBLISH=true tap --no-check-coverage test/build/**.test.js",
21
+ "prepublishOnly": "PREPUBLISH=true tap --no-check-coverage test/build/**.test.js && npm run test:validator:integrity",
21
22
  "test": "npm run lint && npm run unit && npm run test:typescript",
22
23
  "test:ci": "npm run unit -- -R terse --cov --coverage-report=lcovonly && npm run test:typescript",
23
24
  "test:report": "npm run lint && npm run unit:report && npm run test:typescript",
25
+ "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",
24
26
  "test:typescript": "tsc test/types/import.ts && tsd",
25
27
  "test:watch": "npm run unit -- -w --no-coverage-report -R terse",
26
28
  "unit": "tap",
@@ -117,6 +119,11 @@
117
119
  "name": "Luis Orbaiceta",
118
120
  "email": "luisorbaiceta@gmail.com",
119
121
  "url": "https://luisorbaiceta.com"
122
+ },
123
+ {
124
+ "name": "Carlos Fuentes",
125
+ "email": "me@metcoder.dev",
126
+ "url": "https://metcoder.dev"
120
127
  }
121
128
  ],
122
129
  "license": "MIT",
@@ -164,7 +171,7 @@
164
171
  "split2": "^4.1.0",
165
172
  "standard": "^17.0.0",
166
173
  "tap": "^16.3.0",
167
- "tsd": "^0.25.0",
174
+ "tsd": "^0.26.0",
168
175
  "typescript": "^4.8.3",
169
176
  "undici": "^5.10.0",
170
177
  "vary": "^1.1.2",
@@ -173,11 +180,11 @@
173
180
  "dependencies": {
174
181
  "@fastify/ajv-compiler": "^3.5.0",
175
182
  "@fastify/error": "^3.0.0",
176
- "@fastify/fast-json-stringify-compiler": "^4.1.0",
183
+ "@fastify/fast-json-stringify-compiler": "^4.2.0",
177
184
  "abstract-logging": "^2.0.1",
178
185
  "avvio": "^8.2.0",
179
186
  "fast-content-type-parse": "^1.0.0",
180
- "find-my-way": "^7.3.0",
187
+ "find-my-way": "^7.6.0",
181
188
  "light-my-request": "^5.6.1",
182
189
  "pino": "^8.5.0",
183
190
  "process-warning": "^2.0.0",