fastify 4.19.2 → 4.20.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.
Files changed (50) hide show
  1. package/.c8rc.json +8 -0
  2. package/.taprc +3 -2
  3. package/SECURITY.md +9 -0
  4. package/docs/Guides/Prototype-Poisoning.md +2 -2
  5. package/docs/Reference/Errors.md +39 -17
  6. package/docs/Reference/Logging.md +1 -1
  7. package/docs/Reference/Plugins.md +4 -0
  8. package/docs/Reference/Routes.md +8 -0
  9. package/docs/Reference/Server.md +38 -0
  10. package/fastify.d.ts +3 -2
  11. package/fastify.js +36 -17
  12. package/lib/context.js +6 -0
  13. package/lib/errors.js +50 -19
  14. package/lib/fourOhFour.js +5 -9
  15. package/lib/handleRequest.js +3 -5
  16. package/lib/hooks.js +91 -25
  17. package/lib/logger.js +40 -3
  18. package/lib/reply.js +3 -9
  19. package/lib/reqIdGenFactory.js +18 -3
  20. package/lib/route.js +14 -61
  21. package/lib/schema-controller.js +2 -0
  22. package/lib/server.js +23 -8
  23. package/lib/symbols.js +1 -0
  24. package/package.json +8 -7
  25. package/test/500s.test.js +22 -0
  26. package/test/childLoggerFactory.test.js +91 -0
  27. package/test/encapsulated-child-logger-factory.test.js +69 -0
  28. package/test/fastify-instance.test.js +43 -10
  29. package/test/inject.test.js +1 -2
  30. package/test/internals/errors.test.js +843 -0
  31. package/test/internals/hookRunner.test.js +22 -8
  32. package/test/internals/initialConfig.test.js +9 -2
  33. package/test/internals/reply.test.js +49 -43
  34. package/test/internals/reqIdGenFactory.test.js +129 -0
  35. package/test/internals/request-validate.test.js +40 -1
  36. package/test/internals/request.test.js +14 -4
  37. package/test/reply-error.test.js +25 -0
  38. package/test/request-id.test.js +131 -0
  39. package/test/route.test.js +135 -0
  40. package/test/server.test.js +64 -2
  41. package/test/types/errors.test-d.ts +82 -0
  42. package/test/types/fastify.test-d.ts +4 -0
  43. package/test/types/instance.test-d.ts +37 -0
  44. package/test/types/reply.test-d.ts +1 -0
  45. package/test/types/route.test-d.ts +3 -0
  46. package/types/errors.d.ts +29 -23
  47. package/types/instance.d.ts +33 -7
  48. package/types/logger.d.ts +25 -0
  49. package/types/reply.d.ts +1 -1
  50. package/types/route.d.ts +2 -1
package/.c8rc.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "exclude": [
3
+ "lib/configValidator.js",
4
+ "lib/error-serializer.js",
5
+ "build/build-error-serializer.js",
6
+ "test/*"
7
+ ]
8
+ }
package/.taprc CHANGED
@@ -1,8 +1,9 @@
1
1
  ts: false
2
2
  jsx: false
3
3
  flow: false
4
- check-coverage: true
5
- coverage: true
4
+ # the coverage is performed by c8
5
+ check-coverage: false
6
+ coverage: false
6
7
  node-arg: --allow-natives-syntax
7
8
 
8
9
  files:
package/SECURITY.md CHANGED
@@ -27,6 +27,15 @@ reported vulnerabilities:
27
27
  validity of the report. In any case, the report should follow the same process
28
28
  as outlined below of inviting the maintainers to review and accept the
29
29
  vulnerability.
30
+ * ***Do not*** attempt to show CI/CD vulnerabilities by creating new pull
31
+ requests to any of the Fastify organization's repositories. Doing so will
32
+ result in a [content report][cr] to GitHub as an unsolicited exploit.
33
+ The proper way to provide such reports is by creating a new repository,
34
+ configured in the same manner as the repository you would like to submit
35
+ a report about, and with a pull request to your own repository showing
36
+ the proof of concept.
37
+
38
+ [cr]: https://docs.github.com/en/communities/maintaining-your-safety-on-github/reporting-abuse-or-spam#reporting-an-issue-or-pull-request
30
39
 
31
40
  ### Vulnerabilities found outside this process
32
41
 
@@ -13,8 +13,8 @@ open-source software and the limitations of existing communication channels.
13
13
 
14
14
  But first, if we use a JavaScript framework to process incoming JSON data, take
15
15
  a moment to read up on [Prototype Poisoning](https://medium.com/intrinsic/javascript-prototype-poisoning-vulnerabilities-in-the-wild-7bc15347c96)
16
- in general, and the specific [technical details]
17
- (https://github.com/hapijs/hapi/issues/3916) of this issue.
16
+ in general, and the specific
17
+ [technical details](https://github.com/hapijs/hapi/issues/3916) of this issue.
18
18
  This could be a critical issue so, we might need to verify your own code first.
19
19
  It focuses on specific framework however, any solution that uses `JSON.parse()`
20
20
  to process external data is potentially at risk.
@@ -168,8 +168,6 @@ ajv.plugins option should be an array.
168
168
 
169
169
  Version constraint should be a string.
170
170
 
171
- <a name="FST_ERR_CTP_ALREADY_PRESENT"></a>
172
-
173
171
  #### FST_ERR_CTP_ALREADY_PRESENT
174
172
  <a id="FST_ERR_CTP_ALREADY_PRESENT"></a>
175
173
 
@@ -260,6 +258,11 @@ The hook name must be a string.
260
258
 
261
259
  The hook callback must be a function.
262
260
 
261
+ #### FST_ERR_HOOK_INVALID_ASYNC_HANDLER
262
+ <a id="FST_ERR_HOOK_INVALID_ASYNC_HANDLER"></a>
263
+
264
+ Async function has too many arguments. Async hooks should not use the `done` argument.
265
+
263
266
  #### FST_ERR_HOOK_NOT_SUPPORTED
264
267
  <a id="FST_ERR_HOOK_NOT_SUPPORTED"></a>
265
268
 
@@ -271,8 +274,8 @@ The hook is not supported.
271
274
  You must register a plugin for handling middlewares,
272
275
  visit [`Middleware`](./Middleware.md) for more info.
273
276
 
274
- <a name="FST_ERR_HOOK_TIMEOUT"></a>
275
277
  #### FST_ERR_HOOK_TIMEOUT
278
+ <a id="FST_ERR_HOOK_TIMEOUT"></a>
276
279
 
277
280
  A callback for a hook timed out
278
281
 
@@ -327,11 +330,21 @@ Called `reply.trailer` with an invalid header name.
327
330
 
328
331
  Called `reply.trailer` with an invalid type. Expected a function.
329
332
 
333
+ #### FST_ERR_FAILED_ERROR_SERIALIZATION
334
+ <a id="FST_ERR_FAILED_ERROR_SERIALIZATION"></a>
335
+
336
+ Failed to serialize an error.
337
+
330
338
  #### FST_ERR_MISSING_SERIALIZATION_FN
331
339
  <a id="FST_ERR_MISSING_SERIALIZATION_FN"></a>
332
340
 
333
341
  Missing serialization function.
334
342
 
343
+ #### FST_ERR_MISSING_CONTENTTYPE_SERIALIZATION_FN
344
+ <a id="FST_ERR_MISSING_CONTENTTYPE_SERIALIZATION_FN"></a>
345
+
346
+ Missing serialization function.
347
+
335
348
  #### FST_ERR_REQ_INVALID_VALIDATION_INVOCATION
336
349
  <a id="FST_ERR_REQ_INVALID_VALIDATION_INVOCATION"></a>
337
350
 
@@ -348,6 +361,11 @@ The schema provided does not have `$id` property.
348
361
 
349
362
  A schema with the same `$id` already exists.
350
363
 
364
+ #### FST_ERR_SCH_CONTENT_MISSING_SCHEMA
365
+ <a id="FST_ERR_SCH_CONTENT_MISSING_SCHEMA"></a>
366
+
367
+ A schema is missing for the corresponding content type.
368
+
351
369
  #### FST_ERR_SCH_DUPLICATE
352
370
  <a id="FST_ERR_SCH_DUPLICATE"></a>
353
371
 
@@ -384,8 +402,8 @@ Invalid initialization options.
384
402
  Cannot set forceCloseConnections to `idle` as your HTTP server
385
403
  does not support `closeIdleConnections` method.
386
404
 
387
- <a name="FST_ERR_DUPLICATED_ROUTE"></a>
388
405
  #### FST_ERR_DUPLICATED_ROUTE
406
+ <a id="FST_ERR_DUPLICATED_ROUTE"></a>
389
407
 
390
408
  The HTTP method already has a registered controller for that URL
391
409
 
@@ -394,7 +412,7 @@ The HTTP method already has a registered controller for that URL
394
412
 
395
413
  The router received an invalid url.
396
414
 
397
- ### FST_ERR_ASYNC_CONSTRAINT
415
+ #### FST_ERR_ASYNC_CONSTRAINT
398
416
  <a id="FST_ERR_ASYNC_CONSTRAINT"></a>
399
417
 
400
418
  The router received an error when using asynchronous constraints.
@@ -469,38 +487,42 @@ Fastify is already listening.
469
487
 
470
488
  Installed Fastify plugin mismatched expected version.
471
489
 
472
- <a name="FST_ERR_PLUGIN_CALLBACK_NOT_FN"></a>
473
-
474
490
  #### FST_ERR_PLUGIN_CALLBACK_NOT_FN
491
+ <a id="FST_ERR_PLUGIN_CALLBACK_NOT_FN"></a>
475
492
 
476
493
  Callback for a hook is not a function (mapped directly from `avvio`)
477
494
 
478
- <a name="FST_ERR_PLUGIN_NOT_VALID"></a>
479
-
480
495
  #### FST_ERR_PLUGIN_NOT_VALID
496
+ <a id="FST_ERR_PLUGIN_NOT_VALID"></a>
481
497
 
482
498
  Plugin must be a function or a promise.
483
499
 
484
- <a name="FST_ERR_ROOT_PLG_BOOTED"></a>
485
-
486
500
  #### FST_ERR_ROOT_PLG_BOOTED
501
+ <a id="FST_ERR_ROOT_PLG_BOOTED"></a>
487
502
 
488
503
  Root plugin has already booted (mapped directly from `avvio`)
489
504
 
490
- <a name="FST_ERR_PARENT_PLUGIN_BOOTED"></a>
491
-
492
505
  #### FST_ERR_PARENT_PLUGIN_BOOTED
506
+ <a id="FST_ERR_PARENT_PLUGIN_BOOTED"></a>
493
507
 
494
508
  Impossible to load plugin because the parent (mapped directly from `avvio`)
495
509
 
496
- <a name="FST_ERR_PLUGIN_TIMEOUT"></a>
497
-
498
510
  #### FST_ERR_PLUGIN_TIMEOUT
511
+ <a id="FST_ERR_PLUGIN_TIMEOUT"></a>
499
512
 
500
513
  Plugin did not start in time. Default timeout (in millis): `10000`
501
514
 
502
- <a name="FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE"></a>
503
-
504
515
  #### FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE
516
+ <a id="FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE"></a>
505
517
 
506
518
  The decorator is not present in the instance.
519
+
520
+ #### FST_ERR_VALIDATION
521
+ <a id="FST_ERR_VALIDATION"></a>
522
+
523
+ The Request failed the payload validation.
524
+
525
+ #### FST_ERR_LISTEN_OPTIONS_INVALID
526
+ <a id="FST_ERR_LISTEN_OPTIONS_INVALID"></a>
527
+
528
+ Invalid listen options.
@@ -196,7 +196,7 @@ app.addHook('preHandler', function (req, reply, done) {
196
196
  })
197
197
  ```
198
198
 
199
- **Note**: Care should be take to ensure serializers never throw, as an error
199
+ **Note**: Care should be taken to ensure serializers never throw, as an error
200
200
  thrown from a serializer has the potential to cause the Node process to exit.
201
201
  See the [Pino documentation](https://getpino.io/#/docs/api?id=opt-serializers)
202
202
  on serializers for more information.
@@ -145,6 +145,10 @@ await fastify.ready()
145
145
 
146
146
  await fastify.listen({ port: 3000 })
147
147
  ```
148
+ *Note: Using `await` when registering a plugin loads the plugin
149
+ and the underlying dependency tree, "finalizing" the encapsulation process.
150
+ Any mutations to the plugin after it and its dependencies have been
151
+ loaded will not be reflected in the parent instance.*
148
152
 
149
153
  #### ESM support
150
154
  <a id="esm-support"></a>
@@ -90,6 +90,14 @@ fastify.route(options)
90
90
  To access the default handler, you can access `instance.errorHandler`. Note
91
91
  that this will point to fastify's default `errorHandler` only if a plugin
92
92
  hasn't overridden it already.
93
+ * `childLoggerFactory(logger, binding, opts, rawReq)`: a custom factory function
94
+ that will be called to produce a child logger instance for every request.
95
+ See [`childLoggerFactory`](./Server.md#childloggerfactory) for more info.
96
+ Overrides the default logger factory, and anything set by
97
+ [`setChildLoggerFactory`](./Server.md#setchildloggerfactory), for requests to
98
+ the route. To access the default factory, you can access
99
+ `instance.childLoggerFactory`. Note that this will point to Fastify's default
100
+ `childLoggerFactory` only if a plugin hasn't overridden it already.
93
101
  * `validatorCompiler({ schema, method, url, httpPart })`: function that builds
94
102
  schemas for request validations. See the [Validation and
95
103
  Serialization](./Validation-and-Serialization.md#schema-validator)
@@ -80,6 +80,7 @@ describes the properties available in that options object.
80
80
  - [schemaController](#schemacontroller)
81
81
  - [setNotFoundHandler](#setnotfoundhandler)
82
82
  - [setErrorHandler](#seterrorhandler)
83
+ - [setChildLoggerFactory](#setchildloggerfactory)
83
84
  - [addConstraintStrategy](#addconstraintstrategy)
84
85
  - [hasConstraintStrategy](#hasconstraintstrategy)
85
86
  - [printRoutes](#printroutes)
@@ -91,6 +92,7 @@ describes the properties available in that options object.
91
92
  - [getDefaultJsonParser](#getdefaultjsonparser)
92
93
  - [defaultTextParser](#defaulttextparser)
93
94
  - [errorHandler](#errorhandler)
95
+ - [childLoggerFactory](#childloggerfactory)
94
96
  - [initialConfig](#initialconfig)
95
97
 
96
98
  ### `http`
@@ -1537,6 +1539,35 @@ if (statusCode >= 500) {
1537
1539
  log.error(error)
1538
1540
  }
1539
1541
  ```
1542
+ #### setChildLoggerFactory
1543
+ <a id="set-child-logger-factory"></a>
1544
+
1545
+ `fastify.setChildLoggerFactory(factory(logger, bindings, opts, rawReq))`: Set a
1546
+ function that will be called when creating a child logger instance for each request
1547
+ which allows for modifying or adding child logger bindings and logger options, or
1548
+ returning a completely custom child logger implementation.
1549
+
1550
+ Child logger bindings have a performance advantage over per-log bindings, because
1551
+ they are pre-serialised by Pino when the child logger is created.
1552
+
1553
+ The first parameter is the parent logger instance, followed by the default bindings
1554
+ and logger options which should be passed to the child logger, and finally
1555
+ the raw request (not a Fastify request object). The function is bound with `this`
1556
+ being the Fastify instance.
1557
+
1558
+ For example:
1559
+ ```js
1560
+ const fastify = require('fastify')({
1561
+ childLoggerFactory: function (logger, bindings, opts, rawReq) {
1562
+ // Calculate additional bindings from the request if needed
1563
+ bindings.traceContext = rawReq.headers['x-cloud-trace-context']
1564
+ return logger.child(bindings, opts)
1565
+ }
1566
+ })
1567
+ ```
1568
+
1569
+ The handler is bound to the Fastify instance and is fully encapsulated, so
1570
+ different plugins can set different logger factories.
1540
1571
 
1541
1572
  #### addConstraintStrategy
1542
1573
  <a id="addConstraintStrategy"></a>
@@ -1810,6 +1841,13 @@ fastify.get('/', {
1810
1841
  }, handler)
1811
1842
  ```
1812
1843
 
1844
+ #### childLoggerFactory
1845
+ <a id="childLoggerFactory"></a>
1846
+
1847
+ `fastify.childLoggerFactory` returns the custom logger factory function for the
1848
+ Fastify instance. See the [`childLoggerFactory` config option](#setchildloggerfactory)
1849
+ for more info.
1850
+
1813
1851
  #### initialConfig
1814
1852
  <a id="initial-config"></a>
1815
1853
 
package/fastify.d.ts CHANGED
@@ -14,7 +14,7 @@ import { FastifyContext, FastifyContextConfig } from './types/context'
14
14
  import { FastifyErrorCodes } from './types/errors'
15
15
  import { DoneFuncWithErrOrRes, HookHandlerDoneFunction, RequestPayload, onCloseAsyncHookHandler, onCloseHookHandler, onErrorAsyncHookHandler, onErrorHookHandler, onReadyAsyncHookHandler, onReadyHookHandler, onRegisterHookHandler, onRequestAsyncHookHandler, onRequestHookHandler, onResponseAsyncHookHandler, onResponseHookHandler, onRouteHookHandler, onSendAsyncHookHandler, onSendHookHandler, onTimeoutAsyncHookHandler, onTimeoutHookHandler, preHandlerAsyncHookHandler, preHandlerHookHandler, preParsingAsyncHookHandler, preParsingHookHandler, preSerializationAsyncHookHandler, preSerializationHookHandler, preValidationAsyncHookHandler, preValidationHookHandler, onRequestAbortHookHandler, onRequestAbortAsyncHookHandler } from './types/hooks'
16
16
  import { FastifyListenOptions, FastifyInstance, PrintRoutesOptions } from './types/instance'
17
- import { FastifyBaseLogger, FastifyLoggerInstance, FastifyLoggerOptions, PinoLoggerOptions, FastifyLogFn, LogLevel } from './types/logger'
17
+ import { FastifyBaseLogger, FastifyLoggerInstance, FastifyLoggerOptions, PinoLoggerOptions, FastifyLogFn, LogLevel, Bindings, ChildLoggerOptions } from './types/logger'
18
18
  import { FastifyPluginCallback, FastifyPluginAsync, FastifyPluginOptions, FastifyPlugin } from './types/plugin'
19
19
  import { FastifyRegister, FastifyRegisterOptions, RegisterOptions } from './types/register'
20
20
  import { FastifyReply } from './types/reply'
@@ -106,6 +106,7 @@ declare namespace fastify {
106
106
  serializerOpts?: FJSOptions | Record<string, unknown>,
107
107
  serverFactory?: FastifyServerFactory<RawServer>,
108
108
  caseSensitive?: boolean,
109
+ allowUnsafeRegex?: boolean,
109
110
  requestIdHeader?: string | false,
110
111
  requestIdLogLabel?: string;
111
112
  jsonShorthand?: boolean;
@@ -158,7 +159,7 @@ declare namespace fastify {
158
159
  /**
159
160
  * listener to error events emitted by client connections
160
161
  */
161
- clientErrorHandler?: (error: ConnectionError, socket: Socket) => void
162
+ clientErrorHandler?: (error: ConnectionError, socket: Socket) => void,
162
163
  }
163
164
 
164
165
  export interface ValidationResult {
package/fastify.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const VERSION = '4.19.2'
3
+ const VERSION = '4.20.0'
4
4
 
5
5
  const Avvio = require('avvio')
6
6
  const http = require('http')
@@ -28,20 +28,21 @@ const {
28
28
  kSchemaErrorFormatter,
29
29
  kErrorHandler,
30
30
  kKeepAliveConnections,
31
- kFourOhFourContext
31
+ kChildLoggerFactory
32
32
  } = require('./lib/symbols.js')
33
33
 
34
34
  const { createServer, compileValidateHTTPVersion } = require('./lib/server')
35
35
  const Reply = require('./lib/reply')
36
36
  const Request = require('./lib/request')
37
+ const Context = require('./lib/context.js')
37
38
  const { supportedMethods } = require('./lib/httpMethods')
38
39
  const decorator = require('./lib/decorate')
39
40
  const ContentTypeParser = require('./lib/contentTypeParser')
40
41
  const SchemaController = require('./lib/schema-controller')
41
42
  const { Hooks, hookRunnerApplication, supportedHooks } = require('./lib/hooks')
42
- const { createLogger } = require('./lib/logger')
43
+ const { createLogger, createChildLogger, defaultChildLoggerFactory } = require('./lib/logger')
43
44
  const pluginUtils = require('./lib/pluginUtils')
44
- const reqIdGenFactory = require('./lib/reqIdGenFactory')
45
+ const { reqIdGenFactory } = require('./lib/reqIdGenFactory')
45
46
  const { buildRouting, validateBodyLimitOption } = require('./lib/route')
46
47
  const build404 = require('./lib/fourOhFour')
47
48
  const getSecuredInitialConfig = require('./lib/initialConfigValidation')
@@ -74,14 +75,6 @@ const {
74
75
 
75
76
  const { buildErrorHandler } = require('./lib/error-handler.js')
76
77
 
77
- const onBadUrlContext = {
78
- config: {
79
- },
80
- onSend: [],
81
- onError: [],
82
- [kFourOhFourContext]: null
83
- }
84
-
85
78
  function defaultBuildPrettyMeta (route) {
86
79
  // return a shallow copy of route's sanitized context
87
80
 
@@ -95,6 +88,9 @@ function defaultBuildPrettyMeta (route) {
95
88
  return Object.assign({}, cleanKeys)
96
89
  }
97
90
 
91
+ /**
92
+ * @param {import('./fastify.js').FastifyServerOptions} options
93
+ */
98
94
  function fastify (options) {
99
95
  // Options validations
100
96
  options = options || {}
@@ -113,7 +109,7 @@ function fastify (options) {
113
109
 
114
110
  validateBodyLimitOption(options.bodyLimit)
115
111
 
116
- const requestIdHeader = (options.requestIdHeader === false) ? false : (options.requestIdHeader || defaultInitOptions.requestIdHeader)
112
+ const requestIdHeader = (options.requestIdHeader === false) ? false : (options.requestIdHeader || defaultInitOptions.requestIdHeader).toLowerCase()
117
113
  const genReqId = reqIdGenFactory(requestIdHeader, options.genReqId)
118
114
  const requestIdLogLabel = options.requestIdLogLabel || 'reqId'
119
115
  const bodyLimit = options.bodyLimit || defaultInitOptions.bodyLimit
@@ -235,6 +231,7 @@ function fastify (options) {
235
231
  [kSchemaController]: schemaController,
236
232
  [kSchemaErrorFormatter]: null,
237
233
  [kErrorHandler]: buildErrorHandler(),
234
+ [kChildLoggerFactory]: defaultChildLoggerFactory,
238
235
  [kReplySerializerDefault]: null,
239
236
  [kContentTypeParser]: new ContentTypeParser(
240
237
  bodyLimit,
@@ -340,6 +337,8 @@ function fastify (options) {
340
337
  // custom error handling
341
338
  setNotFoundHandler,
342
339
  setErrorHandler,
340
+ // child logger
341
+ setChildLoggerFactory,
343
342
  // Set fastify initial configuration options read-only object
344
343
  initialConfig,
345
344
  // constraint strategies
@@ -351,11 +350,13 @@ function fastify (options) {
351
350
  listeningOrigin: {
352
351
  get () {
353
352
  const address = this.addresses().slice(-1).pop()
354
- /* istanbul ignore if windows: unix socket is not testable on Windows platform */
353
+ /* ignore if windows: unix socket is not testable on Windows platform */
354
+ /* c8 ignore next 3 */
355
355
  if (typeof address === 'string') {
356
356
  return address
357
357
  }
358
- return `${this[kOptions].https ? 'https' : 'http'}://${address.address}:${address.port}`
358
+ const host = address.family === 'IPv6' ? `[${address.address}]` : address.address
359
+ return `${this[kOptions].https ? 'https' : 'http'}://${host}:${address.port}`
359
360
  }
360
361
  },
361
362
  pluginName: {
@@ -379,6 +380,10 @@ function fastify (options) {
379
380
  configurable: true,
380
381
  get () { return this[kSchemaController].getSerializerCompiler() }
381
382
  },
383
+ childLoggerFactory: {
384
+ configurable: true,
385
+ get () { return this[kChildLoggerFactory] }
386
+ },
382
387
  version: {
383
388
  configurable: true,
384
389
  get () { return VERSION }
@@ -452,6 +457,7 @@ function fastify (options) {
452
457
  // https://github.com/nodejs/node/issues/48604
453
458
  if (!options.serverFactory || fastify[kState].listening) {
454
459
  instance.server.close(function (err) {
460
+ /* c8 ignore next 6 */
455
461
  if (err && err.code !== 'ERR_SERVER_NOT_RUNNING') {
456
462
  done(null)
457
463
  } else {
@@ -465,6 +471,12 @@ function fastify (options) {
465
471
  })
466
472
  })
467
473
 
474
+ // Create bad URL context
475
+ const onBadUrlContext = new Context({
476
+ server: fastify,
477
+ config: {}
478
+ })
479
+
468
480
  // Set the default 404 handler
469
481
  fastify.setNotFoundHandler()
470
482
  fourOhFour.arrange404(fastify)
@@ -706,7 +718,7 @@ function fastify (options) {
706
718
  function onBadUrl (path, req, res) {
707
719
  if (frameworkErrors) {
708
720
  const id = genReqId(req)
709
- const childLogger = logger.child({ reqId: id })
721
+ const childLogger = createChildLogger(onBadUrlContext, logger, req, id)
710
722
 
711
723
  const request = new Request(id, null, req, null, childLogger, onBadUrlContext)
712
724
  const reply = new Reply(res, request, childLogger)
@@ -731,7 +743,7 @@ function fastify (options) {
731
743
  if (err) {
732
744
  if (frameworkErrors) {
733
745
  const id = genReqId(req)
734
- const childLogger = logger.child({ reqId: id })
746
+ const childLogger = createChildLogger(onBadUrlContext, logger, req, id)
735
747
 
736
748
  const request = new Request(id, null, req, null, childLogger, onBadUrlContext)
737
749
  const reply = new Reply(res, request, childLogger)
@@ -803,6 +815,13 @@ function fastify (options) {
803
815
  return this
804
816
  }
805
817
 
818
+ function setChildLoggerFactory (factory) {
819
+ throwIfAlreadyStarted('Cannot call "setChildLoggerFactory"!')
820
+
821
+ this[kChildLoggerFactory] = factory
822
+ return this
823
+ }
824
+
806
825
  function printRoutes (opts = {}) {
807
826
  // includeHooks:true - shortcut to include all supported hooks exported by fastify.Hooks
808
827
  opts.includeMeta = opts.includeHooks ? opts.includeMeta ? supportedHooks.concat(opts.includeMeta) : supportedHooks : opts.includeMeta
package/lib/context.js CHANGED
@@ -5,6 +5,8 @@ const {
5
5
  kReplySerializerDefault,
6
6
  kSchemaErrorFormatter,
7
7
  kErrorHandler,
8
+ kChildLoggerFactory,
9
+ kOptions,
8
10
  kReply,
9
11
  kRequest,
10
12
  kBodyLimit,
@@ -22,6 +24,8 @@ function Context ({
22
24
  schema,
23
25
  handler,
24
26
  config,
27
+ requestIdLogLabel,
28
+ childLoggerFactory,
25
29
  errorHandler,
26
30
  bodyLimit,
27
31
  logLevel,
@@ -51,6 +55,8 @@ function Context ({
51
55
  this.onRequestAbort = null
52
56
  this.config = config
53
57
  this.errorHandler = errorHandler || server[kErrorHandler]
58
+ this.requestIdLogLabel = requestIdLogLabel || server[kOptions].requestIdLogLabel
59
+ this.childLoggerFactory = childLoggerFactory || server[kChildLoggerFactory]
54
60
  this._middie = null
55
61
  this._parserOptions = {
56
62
  limit: bodyLimit || server[kBodyLimit]
package/lib/errors.js CHANGED
@@ -20,32 +20,49 @@ const codes = {
20
20
  FST_ERR_QSP_NOT_FN: createError(
21
21
  'FST_ERR_QSP_NOT_FN',
22
22
  "querystringParser option should be a function, instead got '%s'",
23
- 500
23
+ 500,
24
+ TypeError
24
25
  ),
25
26
  FST_ERR_SCHEMA_CONTROLLER_BUCKET_OPT_NOT_FN: createError(
26
27
  'FST_ERR_SCHEMA_CONTROLLER_BUCKET_OPT_NOT_FN',
27
28
  "schemaController.bucket option should be a function, instead got '%s'",
28
- 500
29
+ 500,
30
+ TypeError
29
31
  ),
30
32
  FST_ERR_SCHEMA_ERROR_FORMATTER_NOT_FN: createError(
31
33
  'FST_ERR_SCHEMA_ERROR_FORMATTER_NOT_FN',
32
34
  "schemaErrorFormatter option should be a non async function. Instead got '%s'.",
33
- 500
35
+ 500,
36
+ TypeError
34
37
  ),
35
38
  FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_OBJ: createError(
36
39
  'FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_OBJ',
37
- "sajv.customOptions option should be an object, instead got '%s'",
38
- 500
40
+ "ajv.customOptions option should be an object, instead got '%s'",
41
+ 500,
42
+ TypeError
39
43
  ),
40
44
  FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_ARR: createError(
41
45
  'FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_ARR',
42
- "sajv.plugins option should be an array, instead got '%s'",
43
- 500
46
+ "ajv.plugins option should be an array, instead got '%s'",
47
+ 500,
48
+ TypeError
44
49
  ),
45
50
  FST_ERR_VERSION_CONSTRAINT_NOT_STR: createError(
46
51
  'FST_ERR_VERSION_CONSTRAINT_NOT_STR',
47
52
  'Version constraint should be a string.',
48
- 500
53
+ 500,
54
+ TypeError
55
+ ),
56
+ FST_ERR_VALIDATION: createError(
57
+ 'FST_ERR_VALIDATION',
58
+ '%s',
59
+ 400
60
+ ),
61
+ FST_ERR_LISTEN_OPTIONS_INVALID: createError(
62
+ 'FST_ERR_LISTEN_OPTIONS_INVALID',
63
+ "Invalid listen options: '%s'",
64
+ 500,
65
+ TypeError
49
66
  ),
50
67
 
51
68
  /**
@@ -116,7 +133,9 @@ const codes = {
116
133
  ),
117
134
  FST_ERR_DEC_DEPENDENCY_INVALID_TYPE: createError(
118
135
  'FST_ERR_DEC_DEPENDENCY_INVALID_TYPE',
119
- "The dependencies of decorator '%s' must be of type Array."
136
+ "The dependencies of decorator '%s' must be of type Array.",
137
+ 500,
138
+ TypeError
120
139
  ),
121
140
  FST_ERR_DEC_MISSING_DEPENDENCY: createError(
122
141
  'FST_ERR_DEC_MISSING_DEPENDENCY',
@@ -179,7 +198,9 @@ const codes = {
179
198
 
180
199
  FST_ERR_LOG_INVALID_LOGGER: createError(
181
200
  'FST_ERR_LOG_INVALID_LOGGER',
182
- "Invalid logger object provided. The logger instance should have these functions(s): '%s'."
201
+ "Invalid logger object provided. The logger instance should have these functions(s): '%s'.",
202
+ 500,
203
+ TypeError
183
204
  ),
184
205
 
185
206
  /**
@@ -197,7 +218,9 @@ const codes = {
197
218
  ),
198
219
  FST_ERR_REP_SENT_VALUE: createError(
199
220
  'FST_ERR_REP_SENT_VALUE',
200
- 'The only possible value for reply.sent is true.'
221
+ 'The only possible value for reply.sent is true.',
222
+ 500,
223
+ TypeError
201
224
  ),
202
225
  FST_ERR_SEND_INSIDE_ONERR: createError(
203
226
  'FST_ERR_SEND_INSIDE_ONERR',
@@ -298,7 +321,8 @@ const codes = {
298
321
  FST_ERR_BAD_URL: createError(
299
322
  'FST_ERR_BAD_URL',
300
323
  "'%s' is not a valid url component",
301
- 400
324
+ 400,
325
+ URIError
302
326
  ),
303
327
  FST_ERR_ASYNC_CONSTRAINT: createError(
304
328
  'FST_ERR_ASYNC_CONSTRAINT',
@@ -314,12 +338,14 @@ const codes = {
314
338
  FST_ERR_INVALID_URL: createError(
315
339
  'FST_ERR_INVALID_URL',
316
340
  "URL must be a string. Received '%s'",
317
- 400
341
+ 400,
342
+ TypeError
318
343
  ),
319
344
  FST_ERR_ROUTE_OPTIONS_NOT_OBJ: createError(
320
345
  'FST_ERR_ROUTE_OPTIONS_NOT_OBJ',
321
346
  'Options for "%s:%s" route must be an object',
322
- 500
347
+ 500,
348
+ TypeError
323
349
  ),
324
350
  FST_ERR_ROUTE_DUPLICATED_HANDLER: createError(
325
351
  'FST_ERR_ROUTE_DUPLICATED_HANDLER',
@@ -329,7 +355,8 @@ const codes = {
329
355
  FST_ERR_ROUTE_HANDLER_NOT_FN: createError(
330
356
  'FST_ERR_ROUTE_HANDLER_NOT_FN',
331
357
  'Error Handler for %s:%s route, if defined, must be a function',
332
- 500
358
+ 500,
359
+ TypeError
333
360
  ),
334
361
  FST_ERR_ROUTE_MISSING_HANDLER: createError(
335
362
  'FST_ERR_ROUTE_MISSING_HANDLER',
@@ -339,7 +366,8 @@ const codes = {
339
366
  FST_ERR_ROUTE_METHOD_INVALID: createError(
340
367
  'FST_ERR_ROUTE_METHOD_INVALID',
341
368
  'Provided method is invalid!',
342
- 500
369
+ 500,
370
+ TypeError
343
371
  ),
344
372
  FST_ERR_ROUTE_METHOD_NOT_SUPPORTED: createError(
345
373
  'FST_ERR_ROUTE_METHOD_NOT_SUPPORTED',
@@ -358,9 +386,10 @@ const codes = {
358
386
  TypeError
359
387
  ),
360
388
  FST_ERR_ROUTE_REWRITE_NOT_STR: createError(
361
- 'FST_ERR_ROUTE_BODY_LIMIT_OPTION_NOT_INT',
389
+ 'FST_ERR_ROUTE_REWRITE_NOT_STR',
362
390
  'Rewrite url for "%s" needs to be of type "string" but received "%s"',
363
- 500
391
+ 500,
392
+ TypeError
364
393
  ),
365
394
 
366
395
  /**
@@ -396,7 +425,9 @@ const codes = {
396
425
  */
397
426
  FST_ERR_PLUGIN_CALLBACK_NOT_FN: createError(
398
427
  'FST_ERR_PLUGIN_CALLBACK_NOT_FN',
399
- 'fastify-plugin: %s'
428
+ 'fastify-plugin: %s',
429
+ 500,
430
+ TypeError
400
431
  ),
401
432
  FST_ERR_PLUGIN_NOT_VALID: createError(
402
433
  'FST_ERR_PLUGIN_NOT_VALID',