fastify 3.6.0 → 3.7.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.
@@ -30,7 +30,7 @@ fastify.addContentTypeParser('application/jsoff', async function (request, paylo
30
30
  })
31
31
 
32
32
  // Can use default JSON/Text parser for different content Types
33
- fastify.addContentTypeParser('text/json', { parseAs: 'string' }, fastify.getDefaultJsonParser('ignore', 'ignore')
33
+ fastify.addContentTypeParser('text/json', { parseAs: 'string' }, fastify.getDefaultJsonParser('ignore', 'ignore'))
34
34
  ```
35
35
 
36
36
  You can also use the `hasContentTypeParser` API to find if a specific content type parser already exists.
package/docs/Ecosystem.md CHANGED
@@ -17,6 +17,7 @@ Plugins maintained by the fastify team are listed under [Core](#core) while plug
17
17
  - [`fastify-compress`](https://github.com/fastify/fastify-compress) Fastify compression utils.
18
18
  - [`fastify-cookie`](https://github.com/fastify/fastify-cookie) Parse and set cookie headers.
19
19
  - [`fastify-cors`](https://github.com/fastify/fastify-cors) Enables the use of CORS in a Fastify application.
20
+ - [`fastify-csrf`](https://github.com/fastify/fastify-csrf) A plugin for adding [CSRF](https://en.wikipedia.org/wiki/Cross-site_request_forgery) protection to Fastify.
20
21
  - [`fastify-elasticsearch`](https://github.com/fastify/fastify-elasticsearch) Plugin to share the same ES client.
21
22
  - [`fastify-env`](https://github.com/fastify/fastify-env) Load and check configuration.
22
23
  - [`fastify-etag`](https://github.com/fastify/fastify-etag) Automatically generate etags for HTTP responses.
@@ -65,7 +66,6 @@ Plugins maintained by the fastify team are listed under [Core](#core) while plug
65
66
  - [`fastify-cloudevents`](https://github.com/smartiniOnGitHub/fastify-cloudevents) Fastify plugin to generate and forward Fastify events in the Cloudevents format.
66
67
  - [`fastify-cockroachdb`](https://github.com/alex-ppg/fastify-cockroachdb) Fastify plugin to connect to a CockroachDB PostgreSQL instance via the Sequelize ORM.
67
68
  - [`fastify-couchdb`](https://github.com/nigelhanlon/fastify-couchdb) Fastify plugin to add CouchDB support via [nano](https://github.com/apache/nano).
68
- - [`fastify-csrf`](https://github.com/Tarang11/fastify-csrf) A csrf plugin for Fastify.
69
69
  - [`fastify-decorators`](https://github.com/L2jLiga/fastify-decorators) Fastify plugin that provides the set of TypeScript decorators.
70
70
  - [`fastify-dynamodb`](https://github.com/matrus2/fastify-dynamodb) AWS DynamoDB plugin for Fastify. It exposes [AWS.DynamoDB.DocumentClient()](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html) object.
71
71
  - [`fastify-dynareg`](https://github.com/greguz/fastify-dynareg) Dynamic plugin register for Fastify.
package/docs/Routes.md CHANGED
@@ -51,7 +51,7 @@ They need to be in
51
51
  * `onSend(request, reply, payload, done)`: a [function](Hooks.md#route-hooks) called right before a response is sent, it could also be an array of functions.
52
52
  * `onResponse(request, reply, done)`: a [function](Hooks.md#onresponse) called when a response has been sent, so you will not be able to send more data to the client. It could also be an array of functions.
53
53
  * `handler(request, reply)`: the function that will handle this request. The [Fastify server](Server.md) will be bound to `this` when the handler is called. Note: using an arrow function will break the binding of `this`.
54
- * `errorHandler(error, request, reply)`: a custom error handler for the scope of the request. Overrides the default error global handler, and anything set by [`setErrorHandler`](Server.md#setErrorHandler), for requests to the route.
54
+ * `errorHandler(error, request, reply)`: a custom error handler for the scope of the request. Overrides the default error global handler, and anything set by [`setErrorHandler`](Server.md#setErrorHandler), for requests to the route. To access the default handler, you can access `instance.errorHandler`. Note that this will point to fastify's default `errorHandler` only if a plugin hasn't overridden it already.
55
55
  * `validatorCompiler({ schema, method, url, httpPart })`: function that builds schemas for request validations. See the [Validation and Serialization](Validation-and-Serialization.md#schema-validator) documentation.
56
56
  * `serializerCompiler({ { schema, method, url, httpStatus } })`: function that builds schemas for response serialization. See the [Validation and Serialization](Validation-and-Serialization.md#schema-serializer) documentation.
57
57
  * `schemaErrorFormatter(errors, dataVar)`: function that formats the errors from the validation compiler. See the [Validation and Serialization](Validation-and-Serialization.md#error-handling) documentation. Overrides the global schema error formatter handler, and anything set by `setSchemaErrorFormatter`, for requests to the route.
package/docs/Server.md CHANGED
@@ -850,7 +850,7 @@ fastify.setErrorHandler(function (error, request, reply) {
850
850
  })
851
851
  ```
852
852
 
853
- Fastify is provided with a default function that is called if no error handler is set and that logs the error with respect to its `statusCode`:
853
+ Fastify is provided with a default function that is called if no error handler is set. It can be accessed using `fastify.errorHandler` and it logs the error with respect to its `statusCode`.
854
854
 
855
855
  ```js
856
856
  var statusCode = error.statusCode
@@ -901,14 +901,31 @@ fastify.addContentTypeParser('text/json', { asString: true }, fastify.getDefault
901
901
 
902
902
 
903
903
  <a name="defaultTextParser"></a>
904
- #### defaultTextParser
904
+ #### defaultTextParser
905
905
 
906
- `fastify.defaultTextParser()` can be used to parse content as plain text.
906
+ `fastify.defaultTextParser()` can be used to parse content as plain text.
907
907
 
908
908
  ```js
909
909
  fastify.addContentTypeParser('text/json', { asString: true }, fastify.defaultTextParser())
910
910
  ```
911
911
 
912
+ <a name="errorHandler"></a>
913
+ #### errorHandler
914
+
915
+ `fastify.errorHandler` can be used to handle errors using fastify's default error handler.
916
+
917
+ ```js
918
+ fastify.get('/', {
919
+ errorHandler: (error, request, reply) => {
920
+ if (error.code === 'SOMETHING_SPECIFIC') {
921
+ reply.send({ custom: 'response' })
922
+ return
923
+ }
924
+
925
+ fastify.errorHandler(error, request, response)
926
+ }
927
+ }, handler)
928
+ ```
912
929
 
913
930
  <a name="initial-config"></a>
914
931
  #### initialConfig
package/fastify.js CHANGED
@@ -26,7 +26,8 @@ const {
26
26
  kState,
27
27
  kOptions,
28
28
  kPluginNameChain,
29
- kSchemaErrorFormatter
29
+ kSchemaErrorFormatter,
30
+ kErrorHandler
30
31
  } = require('./lib/symbols.js')
31
32
 
32
33
  const { createServer } = require('./lib/server')
@@ -58,6 +59,21 @@ const onBadUrlContext = {
58
59
  onError: []
59
60
  }
60
61
 
62
+ function defaultErrorHandler (error, request, reply) {
63
+ if (reply.statusCode >= 500) {
64
+ reply.log.error(
65
+ { req: request, res: reply, err: error },
66
+ error && error.message
67
+ )
68
+ } else if (reply.statusCode >= 400) {
69
+ reply.log.info(
70
+ { res: reply, err: error },
71
+ error && error.message
72
+ )
73
+ }
74
+ reply.send(error)
75
+ }
76
+
61
77
  function fastify (options) {
62
78
  // Options validations
63
79
  options = options || {}
@@ -161,6 +177,7 @@ function fastify (options) {
161
177
  [kSchemas]: schemas,
162
178
  [kValidatorCompiler]: null,
163
179
  [kSchemaErrorFormatter]: options.schemaErrorFormatter,
180
+ [kErrorHandler]: defaultErrorHandler,
164
181
  [kSerializerCompiler]: null,
165
182
  [kReplySerializerDefault]: null,
166
183
  [kContentTypeParser]: new ContentTypeParser(
@@ -274,6 +291,11 @@ function fastify (options) {
274
291
  }
275
292
  return version
276
293
  }
294
+ },
295
+ errorHandler: {
296
+ get () {
297
+ return this[kErrorHandler]
298
+ }
277
299
  }
278
300
  })
279
301
 
@@ -561,7 +583,7 @@ function fastify (options) {
561
583
  function setErrorHandler (func) {
562
584
  throwIfAlreadyStarted('Cannot call "setErrorHandler" when fastify instance is already started!')
563
585
 
564
- this._errorHandler = func.bind(this)
586
+ this[kErrorHandler] = func.bind(this)
565
587
  return this
566
588
  }
567
589
  }
package/lib/context.js CHANGED
@@ -17,7 +17,7 @@ function Context (schema, handler, Reply, Request, contentTypeParser, config, er
17
17
  this.preHandler = null
18
18
  this.onResponse = null
19
19
  this.config = config
20
- this.errorHandler = errorHandler || defaultErrorHandler
20
+ this.errorHandler = errorHandler
21
21
  this._middie = null
22
22
  this._parserOptions = { limit: bodyLimit || null }
23
23
  this.logLevel = logLevel
@@ -28,21 +28,6 @@ function Context (schema, handler, Reply, Request, contentTypeParser, config, er
28
28
  this.schemaErrorFormatter = schemaErrorFormatter || defaultSchemaErrorFormatter
29
29
  }
30
30
 
31
- function defaultErrorHandler (error, request, reply) {
32
- if (reply.statusCode >= 500) {
33
- reply.log.error(
34
- { req: request, res: reply, err: error },
35
- error && error.message
36
- )
37
- } else if (reply.statusCode >= 400) {
38
- reply.log.info(
39
- { res: reply, err: error },
40
- error && error.message
41
- )
42
- }
43
- reply.send(error)
44
- }
45
-
46
31
  function defaultSchemaErrorFormatter (errors, dataVar) {
47
32
  var text = ''
48
33
  var separator = ', '
package/lib/errors.js CHANGED
@@ -171,8 +171,8 @@ const codes = {
171
171
  /**
172
172
  * wrapThenable
173
173
  */
174
- FST_ERR_PROMISE_NOT_FULLFILLED: createError(
175
- 'FST_ERR_PROMISE_NOT_FULLFILLED',
174
+ FST_ERR_PROMISE_NOT_FULFILLED: createError(
175
+ 'FST_ERR_PROMISE_NOT_FULFILLED',
176
176
  "Promise may not be fulfilled with 'undefined' when statusCode is not 204"
177
177
  ),
178
178
 
package/lib/fourOhFour.js CHANGED
@@ -15,7 +15,8 @@ const {
15
15
  kBodyLimit,
16
16
  kLogLevel,
17
17
  kFourOhFourContext,
18
- kHooks
18
+ kHooks,
19
+ kErrorHandler
19
20
  } = require('./symbols.js')
20
21
  const { lifecycleHooks } = require('./hooks')
21
22
  const fourOhFourContext = {
@@ -28,7 +29,7 @@ const fourOhFourContext = {
28
29
  /**
29
30
  * Each fastify instance have a:
30
31
  * kFourOhFourLevelInstance: point to a fastify instance that has the 404 handler setted
31
- * kCanSetNotFoundHandler: bool to track if the 404 handler has alredy been set
32
+ * kCanSetNotFoundHandler: bool to track if the 404 handler has already been set
32
33
  * kFourOhFour: the singleton instance of this 404 module
33
34
  * kFourOhFourContext: the context in the reply object where the handler will be executed
34
35
  */
@@ -124,7 +125,7 @@ function fourOhFour (options) {
124
125
  this[kRequest],
125
126
  this[kContentTypeParser],
126
127
  opts.config || {},
127
- this._errorHandler,
128
+ this[kErrorHandler],
128
129
  this[kBodyLimit],
129
130
  this[kLogLevel]
130
131
  )
package/lib/reply.js CHANGED
@@ -303,9 +303,9 @@ Reply.prototype.getResponseTime = function () {
303
303
  // - https://github.com/fastify/fastify/issues/1864 for the discussions
304
304
  // - https://promisesaplus.com/ for the definition of thenable
305
305
  // - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then for the signature
306
- Reply.prototype.then = function (fullfilled, rejected) {
306
+ Reply.prototype.then = function (fulfilled, rejected) {
307
307
  if (this.sent) {
308
- fullfilled()
308
+ fulfilled()
309
309
  return
310
310
  }
311
311
 
@@ -317,7 +317,7 @@ Reply.prototype.then = function (fullfilled, rejected) {
317
317
  rejected(err)
318
318
  }
319
319
  } else {
320
- fullfilled()
320
+ fulfilled()
321
321
  }
322
322
  })
323
323
  }
package/lib/route.js CHANGED
@@ -40,7 +40,8 @@ const {
40
40
  kRequest,
41
41
  kRequestPayloadStream,
42
42
  kDisableRequestLogging,
43
- kSchemaErrorFormatter
43
+ kSchemaErrorFormatter,
44
+ kErrorHandler
44
45
  } = require('./symbols.js')
45
46
 
46
47
  function buildRouting (options) {
@@ -213,7 +214,7 @@ function buildRouting (options) {
213
214
  this[kRequest],
214
215
  this[kContentTypeParser],
215
216
  config,
216
- opts.errorHandler || this._errorHandler,
217
+ opts.errorHandler || this[kErrorHandler],
217
218
  opts.bodyLimit,
218
219
  opts.logLevel,
219
220
  opts.logSerializers,
package/lib/symbols.js CHANGED
@@ -38,7 +38,8 @@ const keys = {
38
38
  kDisableRequestLogging: Symbol('fastify.disableRequestLogging'),
39
39
  kPluginNameChain: Symbol('fastify.pluginNameChain'),
40
40
  // This symbol is only meant to be used for fastify tests and should not be used for any other purpose
41
- kTestInternals: Symbol('fastify.testInternals')
41
+ kTestInternals: Symbol('fastify.testInternals'),
42
+ kErrorHandler: Symbol('fastify.errorHandler')
42
43
  }
43
44
 
44
45
  module.exports = keys
package/lib/validation.js CHANGED
@@ -97,6 +97,7 @@ function validate (context, request) {
97
97
 
98
98
  function wrapValidationError (result, dataVar, schemaErrorFormatter) {
99
99
  if (result instanceof Error) {
100
+ result.validationContext = result.validationContext || dataVar
100
101
  return result
101
102
  }
102
103
 
@@ -6,7 +6,7 @@ const {
6
6
  kReplySentOverwritten
7
7
  } = require('./symbols')
8
8
 
9
- const { FST_ERR_PROMISE_NOT_FULLFILLED } = require('./errors')
9
+ const { FST_ERR_PROMISE_NOT_FULFILLED } = require('./errors')
10
10
 
11
11
  function wrapThenable (thenable, reply) {
12
12
  thenable.then(function (payload) {
@@ -27,7 +27,7 @@ function wrapThenable (thenable, reply) {
27
27
  reply.send(err)
28
28
  }
29
29
  } else if (reply[kReplySent] === false) {
30
- reply.log.error({ err: new FST_ERR_PROMISE_NOT_FULLFILLED() }, "Promise may not be fulfilled with 'undefined' when statusCode is not 204")
30
+ reply.log.error({ err: new FST_ERR_PROMISE_NOT_FULFILLED() }, "Promise may not be fulfilled with 'undefined' when statusCode is not 204")
31
31
  }
32
32
  }, function (err) {
33
33
  if (reply[kReplySentOverwritten] === true) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fastify",
3
- "version": "3.6.0",
3
+ "version": "3.7.0",
4
4
  "description": "Fast and low overhead web framework, for Node.js",
5
5
  "main": "fastify.js",
6
6
  "type": "commonjs",
@@ -138,7 +138,7 @@
138
138
  "eslint-plugin-standard": "^4.0.1",
139
139
  "events.once": "^2.0.2",
140
140
  "fast-json-body": "^1.1.0",
141
- "fastify-plugin": "^2.1.0",
141
+ "fastify-plugin": "^3.0.0",
142
142
  "fluent-schema": "^1.0.0",
143
143
  "form-data": "^3.0.0",
144
144
  "frameguard": "^3.1.0",
@@ -176,7 +176,7 @@
176
176
  "fastify-warning": "^0.2.0",
177
177
  "find-my-way": "^3.0.0",
178
178
  "flatstr": "^1.0.12",
179
- "light-my-request": "^4.1.0",
179
+ "light-my-request": "^4.2.0",
180
180
  "pino": "^6.2.1",
181
181
  "proxy-addr": "^2.0.5",
182
182
  "readable-stream": "^3.4.0",
@@ -3,6 +3,7 @@
3
3
  const sget = require('simple-get').concat
4
4
  const { test } = require('tap')
5
5
  const Fastify = require('..')
6
+ const semver = require('semver')
6
7
 
7
8
  process.removeAllListeners('warning')
8
9
 
@@ -129,3 +130,33 @@ test('Should emit a warning when using payload less preParsing hook', t => {
129
130
  })
130
131
  })
131
132
  })
133
+
134
+ if (semver.gte(process.versions.node, '13.0.0')) {
135
+ test('Should emit a warning when accessing request.connection instead of request.socket on Node process greater than 13.0.0', t => {
136
+ t.plan(4)
137
+
138
+ process.on('warning', onWarning)
139
+ function onWarning (warning) {
140
+ t.strictEqual(warning.name, 'FastifyDeprecation')
141
+ t.strictEqual(warning.code, 'FSTDEP005')
142
+ t.strictEqual(warning.message, 'You are accessing the deprecated "request.connection" property. Use "request.socket" instead.')
143
+
144
+ // removed listener before light-my-request emit second warning
145
+ process.removeListener('warning', onWarning)
146
+ }
147
+
148
+ const fastify = Fastify()
149
+
150
+ fastify.get('/', (request, reply) => {
151
+ reply.send(request.connection)
152
+ })
153
+
154
+ fastify.inject({
155
+ method: 'GET',
156
+ path: '/'
157
+ }, (err, res) => {
158
+ t.error(err)
159
+ process.removeListener('warning', onWarning)
160
+ })
161
+ })
162
+ }
@@ -4,7 +4,8 @@ const t = require('tap')
4
4
  const test = t.test
5
5
  const Fastify = require('..')
6
6
  const {
7
- kOptions
7
+ kOptions,
8
+ kErrorHandler
8
9
  } = require('../lib/symbols')
9
10
 
10
11
  test('root fastify instance is an object', t => {
@@ -65,3 +66,34 @@ test('fastify instance get invalid ajv options.plugins', t => {
65
66
  }
66
67
  }))
67
68
  })
69
+
70
+ test('fastify instance should contain default errorHandler', t => {
71
+ t.plan(3)
72
+ const fastify = Fastify()
73
+ t.ok(fastify[kErrorHandler] instanceof Function)
74
+ t.same(fastify.errorHandler, fastify[kErrorHandler])
75
+ t.same(Object.getOwnPropertyDescriptor(fastify, 'errorHandler').set, undefined)
76
+ })
77
+
78
+ test('errorHandler in plugin should be separate from the external one', async t => {
79
+ t.plan(4)
80
+ const fastify = Fastify()
81
+
82
+ fastify.register((instance, opts, next) => {
83
+ const inPluginErrHandler = (_, __, reply) => {
84
+ reply.send({ plugin: 'error-object' })
85
+ }
86
+
87
+ instance.setErrorHandler(inPluginErrHandler)
88
+
89
+ t.notSame(instance.errorHandler, fastify.errorHandler)
90
+ t.equal(instance.errorHandler.name, 'bound inPluginErrHandler')
91
+
92
+ next()
93
+ })
94
+
95
+ await fastify.ready()
96
+
97
+ t.ok(fastify[kErrorHandler] instanceof Function)
98
+ t.same(fastify.errorHandler, fastify[kErrorHandler])
99
+ })
@@ -16,9 +16,6 @@ expectAssignable<FastifyInstance>(server.addSchema({
16
16
  expectType<Record<string, unknown>>(server.getSchemas())
17
17
  expectType<unknown>(server.getSchema('SchemaId'))
18
18
 
19
- expectType<unknown>(server.use(() => {}))
20
- expectType<unknown>(server.use('/foo', () => {}))
21
-
22
19
  expectAssignable<FastifyInstance>(
23
20
  server.setErrorHandler(function (error, request, reply) {
24
21
  expectAssignable<FastifyInstance>(this)
@@ -0,0 +1,16 @@
1
+ import { expectAssignable, expectError } from 'tsd'
2
+ import fastify, { FastifyInstance, FastifyPluginAsync } from '../../fastify'
3
+
4
+ const testPluginOptsAsync: FastifyPluginAsync = async function (_instance, _opts) { }
5
+
6
+ // Type validation
7
+ expectError(fastify().register(testPluginOptsAsync, { prefix: 1 }))
8
+ expectError(fastify().register(testPluginOptsAsync, { logLevel: () => ({}) }))
9
+ expectError(fastify().register(testPluginOptsAsync, { logSerializers: () => ({}) }))
10
+ expectError(fastify().register({}))
11
+
12
+ expectAssignable<FastifyInstance>(
13
+ fastify().register(
14
+ testPluginOptsAsync, { prefix: '/example', logLevel: 'info', logSerializers: { key: (value: any) => `${value}` } }
15
+ )
16
+ )
@@ -97,6 +97,72 @@ test('should be able to use setErrorHandler specify custom validation error', t
97
97
  })
98
98
  })
99
99
 
100
+ test('error inside custom error handler should have validationContext', t => {
101
+ t.plan(1)
102
+
103
+ const fastify = Fastify()
104
+
105
+ fastify.post('/', {
106
+ schema,
107
+ validatorCompiler: ({ schema, method, url, httpPart }) => {
108
+ return function (data) {
109
+ return { error: new Error('this failed') }
110
+ }
111
+ }
112
+ }, function (req, reply) {
113
+ t.fail('should not be here')
114
+ reply.code(200).send(req.body.name)
115
+ })
116
+
117
+ fastify.setErrorHandler(function (error, request, reply) {
118
+ t.strictEqual(error.validationContext, 'body')
119
+ reply.status(500).send(error)
120
+ })
121
+
122
+ fastify.inject({
123
+ method: 'POST',
124
+ payload: {
125
+ name: 'michelangelo',
126
+ work: 'artist'
127
+ },
128
+ url: '/'
129
+ }, () => {})
130
+ })
131
+
132
+ test('error inside custom error handler should have validationContext if specified by custom error handler', t => {
133
+ t.plan(1)
134
+
135
+ const fastify = Fastify()
136
+
137
+ fastify.post('/', {
138
+ schema,
139
+ validatorCompiler: ({ schema, method, url, httpPart }) => {
140
+ return function (data) {
141
+ const error = new Error('this failed')
142
+ error.validationContext = 'customContext'
143
+ return { error: error }
144
+ }
145
+ }
146
+ }, function (req, reply) {
147
+ t.fail('should not be here')
148
+ reply.code(200).send(req.body.name)
149
+ })
150
+
151
+ fastify.setErrorHandler(function (error, request, reply) {
152
+ t.strictEqual(error.validationContext, 'customContext')
153
+ reply.status(500).send(error)
154
+ })
155
+
156
+ fastify.inject({
157
+ method: 'POST',
158
+ payload: {
159
+ name: 'michelangelo',
160
+ work: 'artist'
161
+ },
162
+ url: '/'
163
+ }, () => {})
164
+ })
165
+
100
166
  test('should be able to attach validation to request', t => {
101
167
  t.plan(3)
102
168
 
@@ -59,13 +59,6 @@ export interface FastifyInstance<
59
59
 
60
60
  register: FastifyRegister<FastifyInstance<RawServer, RawRequest, RawReply, Logger> & PromiseLike<undefined>>;
61
61
 
62
- /**
63
- * This method will throw a `FST_ERR_MISSING_MIDDLEWARE` error unless support
64
- * for Express-style middlewares is first enabled. Visit
65
- * https://fastify.io/docs/latest/Middleware/ for more info.
66
- */
67
- use(...args: unknown[]): unknown;
68
-
69
62
  route<
70
63
  RouteGeneric extends RouteGenericInterface = RouteGenericInterface,
71
64
  ContextConfig = ContextConfigDefault
@@ -26,4 +26,5 @@ export type FastifyRegisterOptions<Options> = (RegisterOptions & Options) | (()
26
26
  interface RegisterOptions {
27
27
  prefix?: string;
28
28
  logLevel?: LogLevel;
29
+ logSerializers?: Record<string, (value: any) => string>;
29
30
  }