fastify 5.6.0 → 5.6.2

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 (74) hide show
  1. package/.vscode/settings.json +22 -0
  2. package/SECURITY.md +12 -0
  3. package/SPONSORS.md +1 -0
  4. package/build/build-validation.js +1 -1
  5. package/build/sync-version.js +1 -0
  6. package/docs/Guides/Ecosystem.md +5 -0
  7. package/docs/Guides/Fluent-Schema.md +2 -2
  8. package/docs/Reference/Decorators.md +36 -169
  9. package/docs/Reference/Encapsulation.md +5 -1
  10. package/docs/Reference/Plugins.md +11 -2
  11. package/docs/Reference/Reply.md +4 -1
  12. package/docs/Reference/Server.md +39 -1
  13. package/docs/Reference/Type-Providers.md +2 -2
  14. package/docs/Reference/TypeScript.md +136 -0
  15. package/eslint.config.js +18 -2
  16. package/fastify.d.ts +1 -1
  17. package/fastify.js +183 -168
  18. package/lib/{contentTypeParser.js → content-type-parser.js} +2 -1
  19. package/lib/error-handler.js +2 -2
  20. package/lib/{fourOhFour.js → four-oh-four.js} +4 -2
  21. package/lib/{handleRequest.js → handle-request.js} +1 -1
  22. package/lib/{headRoute.js → head-route.js} +13 -1
  23. package/lib/{initialConfigValidation.js → initial-config-validation.js} +1 -1
  24. package/lib/{pluginOverride.js → plugin-override.js} +2 -2
  25. package/lib/{pluginUtils.js → plugin-utils.js} +2 -2
  26. package/lib/reply.js +5 -3
  27. package/lib/request.js +5 -0
  28. package/lib/route.js +20 -9
  29. package/lib/server.js +94 -8
  30. package/lib/symbols.js +1 -0
  31. package/lib/validation.js +9 -1
  32. package/lib/warnings.js +1 -1
  33. package/package.json +8 -8
  34. package/test/500s.test.js +191 -0
  35. package/test/child-logger-factory.test.js +3 -3
  36. package/test/content-parser.test.js +2 -1
  37. package/test/decorator-namespace.test._js_ +1 -1
  38. package/test/diagnostics-channel/error-before-handler.test.js +1 -1
  39. package/test/http2/closing.test.js +88 -0
  40. package/test/internals/content-type-parser.test.js +2 -2
  41. package/test/internals/handle-request.test.js +2 -2
  42. package/test/internals/initial-config.test.js +1 -1
  43. package/test/internals/plugin.test.js +2 -2
  44. package/test/internals/reply.test.js +22 -3
  45. package/test/internals/req-id-gen-factory.test.js +1 -1
  46. package/test/promises.test.js +3 -3
  47. package/test/reply-web-stream-locked.test.js +37 -0
  48. package/test/request-error.test.js +116 -0
  49. package/test/route.6.test.js +20 -1
  50. package/test/route.7.test.js +49 -0
  51. package/test/schema-validation.test.js +27 -4
  52. package/test/server.test.js +22 -4
  53. package/test/set-error-handler.test.js +1 -1
  54. package/test/skip-reply-send.test.js +2 -2
  55. package/test/stream.5.test.js +3 -3
  56. package/test/types/fastify.test-d.ts +70 -18
  57. package/test/types/hooks.test-d.ts +6 -1
  58. package/test/types/instance.test-d.ts +35 -15
  59. package/test/types/logger.test-d.ts +18 -6
  60. package/test/types/plugin.test-d.ts +24 -6
  61. package/test/types/register.test-d.ts +108 -33
  62. package/test/types/reply.test-d.ts +23 -6
  63. package/test/types/request.test-d.ts +25 -6
  64. package/test/types/route.test-d.ts +10 -1
  65. package/test/types/schema.test-d.ts +21 -0
  66. package/test/validation-error-handling.test.js +68 -1
  67. package/test/wrap-thenable.test.js +1 -1
  68. package/types/instance.d.ts +2 -2
  69. package/types/schema.d.ts +1 -1
  70. package/test/check.test.js +0 -219
  71. /package/lib/{configValidator.js → config-validator.js} +0 -0
  72. /package/lib/{reqIdGenFactory.js → req-id-gen-factory.js} +0 -0
  73. /package/lib/{wrapThenable.js → wrap-thenable.js} +0 -0
  74. /package/types/{serverFactory.d.ts → server-factory.d.ts} +0 -0
@@ -0,0 +1,22 @@
1
+ {
2
+ "workbench.colorCustomizations": {
3
+ "[GitHub Dark]": {
4
+ "tab.activeBackground": "#0d0d0d",
5
+ "tab.activeBorder": "#ffff00"
6
+ },
7
+ "activityBar.background": "#FBE7B2",
8
+ "activityBar.foreground": "#52358C",
9
+ "activityBar.inactiveForeground": "#616161",
10
+ "activityBar.activeBorder": "#04184d",
11
+ "activityBar.activeBackground": "#C3B48B",
12
+ "activityBar.border": "#C3B48B",
13
+ "titleBar.activeBackground": "#D2BE88",
14
+ "titleBar.activeForeground": "#52358C",
15
+ "titleBar.inactiveBackground": "#bdb59c",
16
+ "titleBar.inactiveForeground": "#616161",
17
+ "titleBar.border": "#C3B48B",
18
+ "statusBar.background": "#E9DBB7",
19
+ "statusBar.foreground": "#52358C",
20
+ "statusBar.border": "#C3B48B"
21
+ }
22
+ }
package/SECURITY.md CHANGED
@@ -110,6 +110,18 @@ Within HackerOne, this is handled through a "public disclosure request".
110
110
  Reference: [HackerOne:
111
111
  Disclosure](https://docs.hackerone.com/hackers/disclosure.html)
112
112
 
113
+ ### Secondary Contact
114
+
115
+ If you do not receive an acknowledgment of your report within 6 business days,
116
+ or if you cannot find a private security contact for the project, you may
117
+ contact the OpenJS Foundation CNA at `security@lists.openjsf.org` for
118
+ assistance.
119
+
120
+ The CNA can help ensure your report is properly acknowledged, assist with
121
+ coordinating disclosure timelines, and assign CVEs when necessary. This is a
122
+ support mechanism to ensure security reports are handled appropriately across
123
+ all OpenJS Foundation projects.
124
+
113
125
  ## The Fastify Security team
114
126
 
115
127
  The core team is responsible for the management of the security program and
package/SPONSORS.md CHANGED
@@ -17,6 +17,7 @@ _Be the first!_
17
17
  - [Val Town, Inc.](https://opencollective.com/valtown)
18
18
  - [Handsontable - JavaScript Data Grid](https://handsontable.com/docs/react-data-grid/?utm_source=Fastify_GH&utm_medium=sponsorship&utm_campaign=library_sponsorship_2024)
19
19
  - [Lokalise - A Localization and Translation Software Tool](https://lokalise.com/?utm_source=Fastify_GH&utm_medium=sponsorship)
20
+ - [Lambdatest](https://www.lambdatest.com/)
20
21
 
21
22
  ## Tier 2
22
23
 
@@ -16,7 +16,7 @@ module.exports.defaultInitOptions = ${JSON.stringify(defaultInitOptions)}
16
16
  /* c8 ignore stop */
17
17
  `
18
18
 
19
- const file = path.join(__dirname, '..', 'lib', 'configValidator.js')
19
+ const file = path.join(__dirname, '..', 'lib', 'config-validator.js')
20
20
  fs.writeFileSync(file, moduleCode)
21
21
  console.log(`Saved ${file} file successfully`)
22
22
  }
@@ -9,3 +9,4 @@ const { version } = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'packa
9
9
  const fastifyJs = path.join(__dirname, '..', 'fastify.js')
10
10
 
11
11
  fs.writeFileSync(fastifyJs, fs.readFileSync(fastifyJs).toString('utf8').replace(/const\s*VERSION\s*=.*/, `const VERSION = '${version}'`))
12
+ console.log(`Synchronized fastify.js VERSION to ${version}`)
@@ -119,6 +119,8 @@ section.
119
119
  HTTP errors and assertions, but also more request and reply methods.
120
120
  - [`@fastify/session`](https://github.com/fastify/session) a session plugin for
121
121
  Fastify.
122
+ - [`@fastify/sse`](https://github.com/fastify/sse) Plugin for Server-Sent Events
123
+ (SSE) support in Fastify.
122
124
  - [`@fastify/static`](https://github.com/fastify/fastify-static) Plugin for
123
125
  serving static files as fast as possible.
124
126
  - [`@fastify/swagger`](https://github.com/fastify/fastify-swagger) Plugin for
@@ -165,6 +167,9 @@ section.
165
167
  A simple way to add a crud in your fastify project.
166
168
  - [`@applicazza/fastify-nextjs`](https://github.com/applicazza/fastify-nextjs)
167
169
  Alternate Fastify and Next.js integration.
170
+ - [`@attaryz/fastify-devtools`](https://github.com/attaryz/fastify-devtools)
171
+ Development tools plugin for Fastify with live request dashboard, replay
172
+ capabilities, and metrics tracking.
168
173
  - [`@blastorg/fastify-aws-dynamodb-cache`](https://github.com/blastorg/fastify-aws-dynamodb-cache)
169
174
  A plugin to help with caching API responses using AWS DynamoDB.
170
175
  - [`@clerk/fastify`](https://github.com/clerkinc/javascript/tree/main/packages/fastify)
@@ -122,5 +122,5 @@ const schema = { body: bodyJsonSchema }
122
122
  fastify.post('/the/url', { schema }, handler)
123
123
  ```
124
124
 
125
- NB You can mix up the `$ref-way` and the `replace-way` when using
126
- `fastify.addSchema`.
125
+ > ℹ️ Note: You can mix up the `$ref-way` and the `replace-way`
126
+ > when using `fastify.addSchema`.
@@ -366,201 +366,68 @@ Will define the `foo` property on the Fastify instance:
366
366
  console.log(fastify.foo) // 'a getter'
367
367
  ```
368
368
 
369
- ### `getDecorator<T>` API
369
+ #### `getDecorator(name)`
370
+ <a id="get-decorator"></a>
370
371
 
371
- Fastify's `getDecorator<T>` API retrieves an existing decorator from the
372
- Fastify instance, `Request`, or `Reply`. If the decorator is not defined, an
373
- `FST_ERR_DEC_UNDECLARED` error is thrown.
372
+ Used to retrieve an existing decorator from the Fastify instance, `Request`, or `Reply`.
373
+ If the decorator is not defined, an `FST_ERR_DEC_UNDECLARED` error is thrown.
374
374
 
375
- #### Use cases
375
+ ```js
376
+ // Get a decorator from the Fastify instance
377
+ const utility = fastify.getDecorator('utility')
376
378
 
377
- **Early Plugin Dependency Validation**
379
+ // Get a decorator from the request object
380
+ const user = request.getDecorator('user')
378
381
 
379
- `getDecorator<T>` on Fastify instance verifies that required decorators are
380
- available at registration time.
382
+ // Get a decorator from the reply object
383
+ const helper = reply.getDecorator('helper')
384
+ ```
381
385
 
382
- For example:
386
+ The `getDecorator` method is useful for dependency validation - it can be used to
387
+ check for required decorators at registration time. If any are missing, it fails
388
+ at boot, ensuring dependencies are available during the request lifecycle.
383
389
 
384
390
  ```js
385
391
  fastify.register(async function (fastify) {
392
+ // Verify the decorator exists before using it
386
393
  const usersRepository = fastify.getDecorator('usersRepository')
387
394
 
388
395
  fastify.get('/users', async function (request, reply) {
389
- // We are sure `usersRepository` exists at runtime
390
396
  return usersRepository.findAll()
391
397
  })
392
398
  })
393
399
  ```
394
400
 
395
- **Handling Missing Decorators**
396
-
397
- Directly accessing a decorator may lead to unexpected behavior if it is not declared:
398
-
399
- ```ts
400
- const user = request.user;
401
- if (user && user.isAdmin) {
402
- // Execute admin tasks.
403
- }
404
- ```
405
-
406
- If `request.user` doesn't exist, then `user` will be set to `undefined`.
407
- This makes it unclear whether the user is unauthenticated or the decorator is missing.
408
-
409
- Using `getDecorator` enforces runtime safety:
410
-
411
- ```ts
412
- // If the decorator is missing, an explicit `FST_ERR_DEC_UNDECLARED`
413
- // error is thrown immediately.
414
- const user = request.getDecorator('user');
415
- if (user && user.isAdmin) {
416
- // Execute admin tasks.
417
- }
418
- ```
419
-
420
- **Alternative to Module Augmentation**
421
-
422
- Decorators are typically typed via module augmentation:
423
-
424
- ```ts
425
- declare module 'fastify' {
426
- interface FastifyInstance {
427
- usersRepository: IUsersRepository
428
- }
429
- interface FastifyRequest {
430
- session: ISession
431
- }
432
- interface FastifyReply {
433
- sendSuccess: SendSuccessFn
434
- }
435
- }
436
- ```
437
-
438
- This approach modifies the Fastify instance globally, which may lead to
439
- conflicts and inconsistent behavior in multi-server setups or with plugin
440
- encapsulation.
441
-
442
- Using `getDecorator<T>` allows to limit types scope:
443
-
444
- ```ts
445
- serverOne.register(async function (fastify) {
446
- const usersRepository = fastify.getDecorator<PostgreUsersRepository>(
447
- 'usersRepository'
448
- )
449
-
450
- fastify.decorateRequest('session', null)
451
- fastify.addHook('onRequest', async (req, reply) => {
452
- // Yes, the request object has a setDecorator method.
453
- // More information will be provided soon.
454
- req.setDecorator('session', { user: 'Jean' })
455
- })
456
-
457
- fastify.get('/me', (request, reply) => {
458
- const session = request.getDecorator<ISession>('session')
459
- reply.send(session)
460
- })
461
- })
462
-
463
- serverTwo.register(async function (fastify) {
464
- const usersRepository = fastify.getDecorator<SqlLiteUsersRepository>(
465
- 'usersRepository'
466
- )
467
-
468
- fastify.decorateReply('sendSuccess', function (data) {
469
- return this.send({ success: true })
470
- })
471
-
472
- fastify.get('/success', async (request, reply) => {
473
- const sendSuccess = reply.getDecorator<SendSuccessFn>('sendSuccess')
474
- await sendSuccess()
475
- })
476
- })
477
- ```
401
+ > ℹ️ Note: For TypeScript users, `getDecorator` supports generic type parameters.
402
+ > See the [TypeScript documentation](/docs/latest/Reference/TypeScript/) for
403
+ > advanced typing examples.
478
404
 
479
- #### Bound functions inference
405
+ #### `setDecorator(name, value)`
406
+ <a id="set-decorator"></a>
480
407
 
481
- To save time, it's common to infer function types instead of
482
- writing them manually:
408
+ Used to safely update the value of a `Request` decorator.
409
+ If the decorator does not exist, a `FST_ERR_DEC_UNDECLARED` error is thrown.
483
410
 
484
- ```ts
485
- function sendSuccess (this: FastifyReply) {
486
- return this.send({ success: true })
487
- }
488
-
489
- export type SendSuccess = typeof sendSuccess
490
- ```
491
-
492
- However, `getDecorator` returns functions with the `this`
493
- context already **bound**, meaning the `this` parameter disappears
494
- from the function signature.
495
-
496
- To correctly type it, you should use `OmitThisParameter` utility:
497
-
498
- ```ts
499
- function sendSuccess (this: FastifyReply) {
500
- return this.send({ success: true })
501
- }
502
-
503
- type BoundSendSuccess = OmitThisParameter<typeof sendSuccess>
504
-
505
- fastify.decorateReply('sendSuccess', sendSuccess)
506
- fastify.get('/success', async (request, reply) => {
507
- const sendSuccess = reply.getDecorator<BoundSendSuccess>('sendSuccess')
508
- await sendSuccess()
509
- })
510
- ```
511
-
512
- ### `Request.setDecorator<T>` Method
513
-
514
- The `setDecorator<T>` method provides a safe and convenient way to
515
- update the value of a `Request` decorator.
516
- If the decorator does not exist, a `FST_ERR_DEC_UNDECLARED` error
517
- is thrown.
518
-
519
- #### Use Cases
520
-
521
- **Runtime Safety**
522
-
523
- A typical way to set a `Request` decorator looks like this:
524
-
525
- ```ts
526
- fastify.decorateRequest('user', '')
527
- fastify.addHook('preHandler', async (req, reply) => {
528
- req.user = 'Bob Dylan'
529
- })
530
- ```
531
-
532
- However, there is no guarantee that the decorator actually exists
533
- unless you manually check beforehand.
534
- Additionally, typos are common, e.g. `account`, `acount`, or `accout`.
535
-
536
- By using `setDecorator`, you are always sure that the decorator exists:
411
+ ```js
412
+ fastify.decorateRequest('user', null)
537
413
 
538
- ```ts
539
- fastify.decorateRequest('user', '')
540
414
  fastify.addHook('preHandler', async (req, reply) => {
541
- // Throws FST_ERR_DEC_UNDECLARED if the decorator does not exist
542
- req.setDecorator('user-with-typo', 'Bob Dylan')
415
+ // Safely set the decorator value
416
+ req.setDecorator('user', 'Bob Dylan')
543
417
  })
544
418
  ```
545
419
 
546
- ---
547
-
548
- **Type Safety**
420
+ The `setDecorator` method provides runtime safety by ensuring the decorator exists
421
+ before setting its value, preventing errors from typos in decorator names.
549
422
 
550
- If the `FastifyRequest` interface does not declare the decorator, you
551
- would typically need to use type assertions:
552
-
553
- ```ts
423
+ ```js
424
+ fastify.decorateRequest('account', null)
554
425
  fastify.addHook('preHandler', async (req, reply) => {
555
- (req as typeof req & { user: string }).user = 'Bob Dylan'
426
+ // This will throw FST_ERR_DEC_UNDECLARED due to typo in decorator name
427
+ req.setDecorator('acount', { id: 123 })
556
428
  })
557
429
  ```
558
430
 
559
- The `setDecorator<T>` method eliminates the need for explicit type
560
- assertions while allowing type safety:
561
-
562
- ```ts
563
- fastify.addHook('preHandler', async (req, reply) => {
564
- req.setDecorator<string>('user', 'Bob Dylan')
565
- })
566
- ```
431
+ > ℹ️ Note: For TypeScript users, see the
432
+ > [TypeScript documentation](/docs/latest/Reference/TypeScript/) for advanced
433
+ > typing examples using `setDecorator<T>`.
@@ -27,7 +27,11 @@ registered within its _grandchild context_.
27
27
 
28
28
  Given that everything in Fastify is a [plugin](./Plugins.md) except for the
29
29
  _root context_, every "context" and "plugin" in this example is a plugin
30
- that can consist of decorators, hooks, plugins, and routes. To put this
30
+ that can consist of decorators, hooks, plugins, and routes. As plugins, they
31
+ must still signal completion either by returning a Promise (e.g., using `async` functions)
32
+ or by calling the `done` function if using the callback style.
33
+
34
+ To put this
31
35
  example into concrete terms, consider a basic scenario of a REST API server
32
36
  with three routes: the first route (`/one`) requires authentication, the
33
37
  second route (`/two`) does not, and the third route (`/three`) has access to
@@ -171,18 +171,27 @@ export default plugin
171
171
  <a id="create-plugin"></a>
172
172
 
173
173
  Creating a plugin is easy. Create a function that takes three parameters: the
174
- `fastify` instance, an `options` object, and the `done` callback.
174
+ `fastify` instance, an `options` object, and the `done` callback. Alternatively,
175
+ use an `async` function and omit the `done` callback.
175
176
 
176
177
  Example:
177
178
  ```js
178
- module.exports = function (fastify, opts, done) {
179
+ module.exports = function callbackPlugin (fastify, opts, done) {
179
180
  fastify.decorate('utility', function () {})
180
181
 
181
182
  fastify.get('/', handler)
182
183
 
183
184
  done()
184
185
  }
186
+
187
+ // Or using async
188
+ module.exports = async function asyncPlugin (fastify, opts) {
189
+ fastify.decorate('utility', function () {})
190
+
191
+ fastify.get('/', handler)
192
+ }
185
193
  ```
194
+
186
195
  `register` can also be used inside another `register`:
187
196
  ```js
188
197
  module.exports = function (fastify, opts, done) {
@@ -369,7 +369,7 @@ charset must be set explicitly.
369
369
  <a id="getserializationfunction"></a>
370
370
 
371
371
  By calling this function using a provided `schema` or `httpStatus`,
372
- and the optional `contentType`, it will return a `serialzation` function
372
+ and the optional `contentType`, it will return a `serialization` function
373
373
  that can be used to serialize diverse inputs. It returns `undefined` if no
374
374
  serialization function was found using either of the provided inputs.
375
375
 
@@ -688,6 +688,9 @@ If you are sending a stream and you have not set a `'Content-Type'` header,
688
688
  As noted above, streams are considered to be pre-serialized, so they will be
689
689
  sent unmodified without response validation.
690
690
 
691
+ See special note about error handling for streams in
692
+ [`setErrorHandler`](./Server.md#seterrorhandler).
693
+
691
694
  ```js
692
695
  const fs = require('node:fs')
693
696
 
@@ -170,6 +170,12 @@ When set to `true`, upon [`close`](#close) the server will iterate the current
170
170
  persistent connections and [destroy their
171
171
  sockets](https://nodejs.org/dist/latest-v16.x/docs/api/net.html#socketdestroyerror).
172
172
 
173
+ When used with HTTP/2 server, it will also close all active HTTP/2 sessions.
174
+
175
+ > ℹ️ Note:
176
+ > Since Node.js v24 active sessions are closed by default
177
+
178
+
173
179
  > ⚠ Warning:
174
180
  > Connections are not inspected to determine if requests have
175
181
  > been completed.
@@ -966,7 +972,7 @@ Fastify uses [find-my-way](https://github.com/delvedor/find-my-way) which suppor
966
972
  separating the path and query string with a `;` character (code 59), e.g. `/dev;foo=bar`.
967
973
  This decision originated from [delvedor/find-my-way#76]
968
974
  (https://github.com/delvedor/find-my-way/issues/76). Thus, this option will support
969
- backwards compatiblilty for the need to split on `;`. To enable support for splitting
975
+ backwards compatibility for the need to split on `;`. To enable support for splitting
970
976
  on `;` set `useSemicolonDelimiter` to `true`.
971
977
 
972
978
  ```js
@@ -1436,6 +1442,8 @@ fastify.mkcol('/', (req, reply) => {
1436
1442
  })
1437
1443
  ```
1438
1444
 
1445
+ > ⚠ Warning:
1446
+ > `addHttpMethod` overrides existing methods.
1439
1447
 
1440
1448
  #### addSchema
1441
1449
  <a id="add-schema"></a>
@@ -1687,6 +1695,9 @@ set it to 500 before calling the error handler.
1687
1695
  sent to the client. Use the `onSend` hook instead.
1688
1696
  - not found (404) errors. Use [`setNotFoundHandler`](#set-not-found-handler)
1689
1697
  instead.
1698
+ - Stream errors thrown during piping into the response socket, as
1699
+ headers/response were already sent to the client.
1700
+ Use custom in-stream data to signal such errors.
1690
1701
 
1691
1702
  ```js
1692
1703
  fastify.setErrorHandler(function (error, request, reply) {
@@ -1716,6 +1727,33 @@ if (statusCode >= 500) {
1716
1727
  > Avoid calling setErrorHandler multiple times in the same scope.
1717
1728
  > See [`allowErrorHandlerOverride`](#allowerrorhandleroverride).
1718
1729
 
1730
+ ##### Custom error handler for stream replies
1731
+ <a id="set-error-handler-stream-replies"></a>
1732
+
1733
+ If `Content-Type` differs between the endpoint and error handler, explicitly
1734
+ define it in both. For example, if the endpoint returns an `application/text`
1735
+ stream and the error handler responds with `application/json`, the error handler
1736
+ must explicitly set `Content-Type`. Otherwise, it will fail serialization with
1737
+ a `500` status code. Alternatively, always respond with serialized data in the
1738
+ error handler by manually calling a serialization method (e.g.,
1739
+ `JSON.stringify`).
1740
+
1741
+ ```js
1742
+ fastify.setErrorHandler((err, req, reply) => {
1743
+ reply
1744
+ .code(400)
1745
+ .type('application/json')
1746
+ .send({ error: err.message })
1747
+ })
1748
+ ```
1749
+
1750
+ ```js
1751
+ fastify.setErrorHandler((err, req, reply) => {
1752
+ reply
1753
+ .code(400)
1754
+ .send(JSON.stringify({ error: err.message }))
1755
+ })
1756
+ ```
1719
1757
 
1720
1758
  #### setChildLoggerFactory
1721
1759
  <a id="set-child-logger-factory"></a>
@@ -88,8 +88,8 @@ server.get('/route', {
88
88
  ```
89
89
 
90
90
  See the [TypeBox
91
- documentation](https://github.com/sinclairzx81/typebox#validation)
92
- for setting up AJV to work with TypeBox.
91
+ documentation](https://sinclairzx81.github.io/typebox/#/docs/overview/2_setup)
92
+ for setting-up AJV to work with TypeBox.
93
93
 
94
94
  ### Zod
95
95
 
@@ -687,6 +687,142 @@ Or even explicit config on tsconfig
687
687
  }
688
688
  ```
689
689
 
690
+ #### `getDecorator<T>`
691
+
692
+ Fastify's `getDecorator<T>` method retrieves decorators with enhanced type safety.
693
+
694
+ The `getDecorator<T>` method supports generic type parameters for enhanced type safety:
695
+
696
+ ```typescript
697
+ // Type-safe decorator retrieval
698
+ const usersRepository = fastify.getDecorator<IUsersRepository>('usersRepository')
699
+ const session = request.getDecorator<ISession>('session')
700
+ const sendSuccess = reply.getDecorator<SendSuccessFn>('sendSuccess')
701
+ ```
702
+
703
+ **Alternative to Module Augmentation**
704
+
705
+ Decorators are typically typed via module augmentation:
706
+
707
+ ```typescript
708
+ declare module 'fastify' {
709
+ interface FastifyInstance {
710
+ usersRepository: IUsersRepository
711
+ }
712
+ interface FastifyRequest {
713
+ session: ISession
714
+ }
715
+ interface FastifyReply {
716
+ sendSuccess: SendSuccessFn
717
+ }
718
+ }
719
+ ```
720
+
721
+ This approach modifies the Fastify instance globally, which may lead to conflicts
722
+ and inconsistent behavior in multi-server setups or with plugin encapsulation.
723
+
724
+ Using `getDecorator<T>` allows limiting types scope:
725
+
726
+ ```typescript
727
+ serverOne.register(async function (fastify) {
728
+ const usersRepository = fastify.getDecorator<PostgreUsersRepository>(
729
+ 'usersRepository'
730
+ )
731
+
732
+ fastify.decorateRequest('session', null)
733
+ fastify.addHook('onRequest', async (req, reply) => {
734
+ req.setDecorator('session', { user: 'Jean' })
735
+ })
736
+
737
+ fastify.get('/me', (request, reply) => {
738
+ const session = request.getDecorator<ISession>('session')
739
+ reply.send(session)
740
+ })
741
+ })
742
+
743
+ serverTwo.register(async function (fastify) {
744
+ const usersRepository = fastify.getDecorator<SqlLiteUsersRepository>(
745
+ 'usersRepository'
746
+ )
747
+
748
+ fastify.decorateReply('sendSuccess', function (data) {
749
+ return this.send({ success: true })
750
+ })
751
+
752
+ fastify.get('/success', async (request, reply) => {
753
+ const sendSuccess = reply.getDecorator<SendSuccessFn>('sendSuccess')
754
+ await sendSuccess()
755
+ })
756
+ })
757
+ ```
758
+
759
+ **Bound Functions Inference**
760
+
761
+ To save time, it is common to infer function types instead of writing them manually:
762
+
763
+ ```typescript
764
+ function sendSuccess (this: FastifyReply) {
765
+ return this.send({ success: true })
766
+ }
767
+
768
+ export type SendSuccess = typeof sendSuccess
769
+ ```
770
+
771
+ However, `getDecorator` returns functions with the `this` context already **bound**,
772
+ meaning the `this` parameter disappears from the function signature.
773
+
774
+ To correctly type it, use the `OmitThisParameter` utility:
775
+
776
+ ```typescript
777
+ function sendSuccess (this: FastifyReply) {
778
+ return this.send({ success: true })
779
+ }
780
+
781
+ type BoundSendSuccess = OmitThisParameter<typeof sendSuccess>
782
+
783
+ fastify.decorateReply('sendSuccess', sendSuccess)
784
+ fastify.get('/success', async (request, reply) => {
785
+ const sendSuccess = reply.getDecorator<BoundSendSuccess>('sendSuccess')
786
+ await sendSuccess()
787
+ })
788
+ ```
789
+
790
+ #### `setDecorator<T>`
791
+
792
+ Fastify's `setDecorator<T>` method provides enhanced type safety for updating request
793
+ decorators.
794
+
795
+ The `setDecorator<T>` method provides enhanced type safety for updating request
796
+ decorators:
797
+
798
+ ```typescript
799
+ fastify.decorateRequest('user', '')
800
+ fastify.addHook('preHandler', async (req, reply) => {
801
+ // Type-safe decorator setting
802
+ req.setDecorator<string>('user', 'Bob Dylan')
803
+ })
804
+ ```
805
+
806
+ **Type Safety Benefits**
807
+
808
+ If the `FastifyRequest` interface does not declare the decorator, type assertions
809
+ are typically needed:
810
+
811
+ ```typescript
812
+ fastify.addHook('preHandler', async (req, reply) => {
813
+ (req as typeof req & { user: string }).user = 'Bob Dylan'
814
+ })
815
+ ```
816
+
817
+ The `setDecorator<T>` method eliminates the need for explicit type assertions
818
+ while providing type safety:
819
+
820
+ ```typescript
821
+ fastify.addHook('preHandler', async (req, reply) => {
822
+ req.setDecorator<string>('user', 'Bob Dylan')
823
+ })
824
+ ```
825
+
690
826
  ## Code Completion In Vanilla JavaScript
691
827
 
692
828
  Vanilla JavaScript can use the published types to provide code completion (e.g.
package/eslint.config.js CHANGED
@@ -4,7 +4,7 @@ const neostandard = require('neostandard')
4
4
  module.exports = [
5
5
  ...neostandard({
6
6
  ignores: [
7
- 'lib/configValidator.js',
7
+ 'lib/config-validator.js',
8
8
  'lib/error-serializer.js',
9
9
  'test/same-shape.test.js',
10
10
  'test/types/import.js'
@@ -13,7 +13,23 @@ module.exports = [
13
13
  }),
14
14
  {
15
15
  rules: {
16
- 'comma-dangle': ['error', 'never']
16
+ 'comma-dangle': ['error', 'never'],
17
+ 'max-len': ['error', {
18
+ code: 120,
19
+ tabWidth: 2,
20
+ ignoreUrls: true,
21
+ ignoreStrings: true,
22
+ ignoreTemplateLiterals: true,
23
+ ignoreRegExpLiterals: true,
24
+ ignoreComments: true,
25
+ ignoreTrailingComments: true
26
+ }]
27
+ }
28
+ },
29
+ {
30
+ files: ['**/*.d.ts'],
31
+ rules: {
32
+ 'max-len': 'off'
17
33
  }
18
34
  }
19
35
  ]
package/fastify.d.ts CHANGED
@@ -29,7 +29,7 @@ import { FastifyReply } from './types/reply'
29
29
  import { FastifyRequest, RequestGenericInterface } from './types/request'
30
30
  import { RouteGenericInterface, RouteHandler, RouteHandlerMethod, RouteOptions, RouteShorthandMethod, RouteShorthandOptions, RouteShorthandOptionsWithHandler } from './types/route'
31
31
  import { FastifySchema, FastifySchemaValidationError, FastifySchemaCompiler, FastifySerializerCompiler, SchemaErrorDataVar, SchemaErrorFormatter } from './types/schema'
32
- import { FastifyServerFactory, FastifyServerFactoryHandler } from './types/serverFactory'
32
+ import { FastifyServerFactory, FastifyServerFactoryHandler } from './types/server-factory'
33
33
  import { FastifyTypeProvider, FastifyTypeProviderDefault, SafePromiseLike } from './types/type-provider'
34
34
  import { ContextConfigDefault, HTTPMethods, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerBase, RawServerDefault, RequestBodyDefault, RequestHeadersDefault, RequestParamsDefault, RequestQuerystringDefault } from './types/utils'
35
35