fastify 4.21.0 → 4.22.1

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 (43) hide show
  1. package/docs/Guides/Database.md +1 -1
  2. package/docs/Guides/Ecosystem.md +11 -3
  3. package/docs/Guides/Getting-Started.md +1 -1
  4. package/docs/Guides/Serverless.md +2 -2
  5. package/docs/Reference/Errors.md +1 -1
  6. package/docs/Reference/HTTP2.md +2 -1
  7. package/docs/Reference/Hooks.md +4 -1
  8. package/docs/Reference/Server.md +5 -1
  9. package/docs/Reference/Validation-and-Serialization.md +1 -1
  10. package/fastify.d.ts +7 -10
  11. package/fastify.js +3 -3
  12. package/lib/contentTypeParser.js +7 -4
  13. package/lib/error-serializer.js +31 -29
  14. package/lib/handleRequest.js +3 -3
  15. package/lib/hooks.js +7 -4
  16. package/lib/logger.js +1 -1
  17. package/lib/pluginOverride.js +10 -3
  18. package/lib/pluginUtils.js +13 -10
  19. package/lib/reply.js +19 -14
  20. package/lib/request.js +2 -2
  21. package/lib/schemas.js +1 -1
  22. package/lib/server.js +4 -4
  23. package/lib/validation.js +1 -1
  24. package/out +25874 -0
  25. package/package.json +7 -6
  26. package/test/bodyLimit.test.js +69 -0
  27. package/test/build/error-serializer.test.js +2 -2
  28. package/test/custom-http-server.test.js +2 -1
  29. package/test/https/custom-https-server.test.js +2 -1
  30. package/test/internals/plugin.test.js +17 -2
  31. package/test/plugin.test.js +26 -0
  32. package/test/post-empty-body.test.js +31 -0
  33. package/test/types/fastify.test-d.ts +8 -3
  34. package/test/types/hooks.test-d.ts +13 -0
  35. package/test/types/instance.test-d.ts +7 -2
  36. package/test/types/request.test-d.ts +1 -1
  37. package/test/types/type-provider.test-d.ts +26 -1
  38. package/types/hooks.d.ts +104 -4
  39. package/types/instance.d.ts +52 -143
  40. package/types/request.d.ts +1 -1
  41. package/types/route.d.ts +6 -1
  42. package/types/schema.d.ts +1 -1
  43. package/types/tsconfig.eslint.json +2 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fastify",
3
- "version": "4.21.0",
3
+ "version": "4.22.1",
4
4
  "description": "Fast and low overhead web framework, for Node.js",
5
5
  "main": "fastify.js",
6
6
  "type": "commonjs",
@@ -14,10 +14,11 @@
14
14
  "coverage:ci": "c8 --reporter=lcov tap --coverage-report=html --no-browser --no-check-coverage",
15
15
  "coverage:ci-check-coverage": "c8 check-coverage --branches 100 --functions 100 --lines 100 --statements 100",
16
16
  "lint": "npm run lint:standard && npm run lint:typescript && npm run lint:markdown",
17
- "lint:fix": "standard --fix",
17
+ "lint:fix": "standard --fix && npm run lint:typescript:fix",
18
18
  "lint:markdown": "markdownlint-cli2",
19
19
  "lint:standard": "standard | snazzy",
20
20
  "lint:typescript": "eslint -c types/.eslintrc.json types/**/*.d.ts test/types/**/*.test-d.ts",
21
+ "lint:typescript:fix": "npm run lint:typescript -- --fix",
21
22
  "prepublishOnly": "cross-env PREPUBLISH=true tap --no-check-coverage test/build/**.test.js && npm run test:validator:integrity",
22
23
  "test": "npm run lint && npm run unit && npm run test:typescript",
23
24
  "test:ci": "npm run unit -- --cov --coverage-report=lcovonly && npm run test:typescript",
@@ -133,11 +134,11 @@
133
134
  "homepage": "https://www.fastify.io/",
134
135
  "devDependencies": {
135
136
  "@fastify/pre-commit": "^2.0.2",
136
- "@sinclair/typebox": "^0.29.1",
137
+ "@sinclair/typebox": "^0.31.1",
137
138
  "@sinonjs/fake-timers": "^11.0.0",
138
139
  "@types/node": "^20.1.0",
139
- "@typescript-eslint/eslint-plugin": "^5.59.2",
140
- "@typescript-eslint/parser": "^5.59.2",
140
+ "@typescript-eslint/eslint-plugin": "^6.3.0",
141
+ "@typescript-eslint/parser": "^6.3.0",
141
142
  "ajv": "^8.12.0",
142
143
  "ajv-errors": "^3.0.0",
143
144
  "ajv-formats": "^2.1.1",
@@ -161,7 +162,7 @@
161
162
  "joi": "^17.9.2",
162
163
  "json-schema-to-ts": "^2.9.1",
163
164
  "JSONStream": "^1.3.5",
164
- "markdownlint-cli2": "^0.8.1",
165
+ "markdownlint-cli2": "^0.9.2",
165
166
  "proxyquire": "^2.1.3",
166
167
  "self-cert": "^2.0.0",
167
168
  "send": "^0.18.0",
@@ -2,6 +2,7 @@
2
2
 
3
3
  const Fastify = require('..')
4
4
  const sget = require('simple-get').concat
5
+ const zlib = require('zlib')
5
6
  const t = require('tap')
6
7
  const test = t.test
7
8
 
@@ -45,6 +46,74 @@ test('bodyLimit', t => {
45
46
  })
46
47
  })
47
48
 
49
+ test('bodyLimit is applied to decoded content', t => {
50
+ t.plan(9)
51
+
52
+ const body = { x: 'x'.repeat(30000) }
53
+ const json = JSON.stringify(body)
54
+ const encoded = zlib.gzipSync(json)
55
+
56
+ const fastify = Fastify()
57
+
58
+ fastify.addHook('preParsing', async (req, reply, payload) => {
59
+ t.equal(req.headers['content-length'], `${encoded.length}`)
60
+ const unzip = zlib.createGunzip()
61
+ Object.defineProperty(unzip, 'receivedEncodedLength', {
62
+ get () {
63
+ return unzip.bytesWritten
64
+ }
65
+ })
66
+ payload.pipe(unzip)
67
+ return unzip
68
+ })
69
+
70
+ fastify.post('/body-limit-40k', {
71
+ bodyLimit: 40000,
72
+ onError: async (req, res, err) => {
73
+ t.fail('should not be called')
74
+ }
75
+ }, (request, reply) => {
76
+ reply.send({ x: request.body.x })
77
+ })
78
+
79
+ fastify.post('/body-limit-20k', {
80
+ bodyLimit: 20000,
81
+ onError: async (req, res, err) => {
82
+ t.equal(err.code, 'FST_ERR_CTP_BODY_TOO_LARGE')
83
+ t.equal(err.statusCode, 413)
84
+ }
85
+ }, (request, reply) => {
86
+ reply.send({ x: 'handler should not be called' })
87
+ })
88
+
89
+ fastify.inject({
90
+ method: 'POST',
91
+ url: '/body-limit-40k',
92
+ headers: {
93
+ 'content-encoding': 'gzip',
94
+ 'content-type': 'application/json'
95
+ },
96
+ payload: encoded
97
+ }, (err, res) => {
98
+ t.error(err)
99
+ t.equal(res.statusCode, 200)
100
+ t.same(res.json(), body)
101
+ })
102
+
103
+ fastify.inject({
104
+ method: 'POST',
105
+ url: '/body-limit-20k',
106
+ headers: {
107
+ 'content-encoding': 'gzip',
108
+ 'content-type': 'application/json'
109
+ },
110
+ payload: encoded
111
+ }, (err, res) => {
112
+ t.error(err)
113
+ t.equal(res.statusCode, 413)
114
+ })
115
+ })
116
+
48
117
  test('default request.routeOptions.bodyLimit should be 1048576', t => {
49
118
  t.plan(4)
50
119
  const fastify = Fastify()
@@ -23,9 +23,9 @@ test('check generated code syntax', async (t) => {
23
23
  t.equal(result[0].fatalErrorCount, 0)
24
24
  })
25
25
 
26
- const isPrebublish = !!process.env.PREPUBLISH
26
+ const isPrepublish = !!process.env.PREPUBLISH
27
27
 
28
- test('ensure the current error serializer is latest', { skip: !isPrebublish }, async (t) => {
28
+ test('ensure the current error serializer is latest', { skip: !isPrepublish }, async (t) => {
29
29
  t.plan(1)
30
30
 
31
31
  const current = await fs.promises.readFile(path.resolve('lib/error-serializer.js'))
@@ -10,8 +10,9 @@ const dns = require('dns').promises
10
10
 
11
11
  test('Should support a custom http server', async t => {
12
12
  const localAddresses = await dns.lookup('localhost', { all: true })
13
+ const minPlan = localAddresses.length - 1 || 1
13
14
 
14
- t.plan((localAddresses.length - 1) + 3)
15
+ t.plan(minPlan + 3)
15
16
 
16
17
  const serverFactory = (handler, opts) => {
17
18
  t.ok(opts.serverFactory, 'it is called once for localhost')
@@ -12,8 +12,9 @@ t.before(buildCertificate)
12
12
 
13
13
  test('Should support a custom https server', async t => {
14
14
  const localAddresses = await dns.lookup('localhost', { all: true })
15
+ const minPlan = localAddresses.length - 1 || 1
15
16
 
16
- t.plan((localAddresses.length - 1) + 3)
17
+ t.plan(minPlan + 3)
17
18
 
18
19
  const serverFactory = (handler, opts) => {
19
20
  t.ok(opts.serverFactory, 'it is called once for localhost')
@@ -29,6 +29,21 @@ test('getPluginName should return plugin name if the file is cached', t => {
29
29
  t.equal(pluginName, expectedPluginName)
30
30
  })
31
31
 
32
+ test('getPluginName should not throw when require.cache is undefined', t => {
33
+ t.plan(1)
34
+ function example () {
35
+ console.log('is just an example')
36
+ }
37
+ const cache = require.cache
38
+ require.cache = undefined
39
+ t.teardown(() => {
40
+ require.cache = cache
41
+ })
42
+ const pluginName = pluginUtilsPublic.getPluginName(example)
43
+
44
+ t.equal(pluginName, 'example')
45
+ })
46
+
32
47
  test("getMeta should return the object stored with the 'plugin-meta' symbol", t => {
33
48
  t.plan(1)
34
49
 
@@ -122,7 +137,7 @@ test('checkDependencies should check if the given dependency is present in the i
122
137
  }
123
138
 
124
139
  function context () {}
125
- context[pluginUtilsPublic.registeredPlugins] = ['plugin']
140
+ context[pluginUtilsPublic.kRegisteredPlugins] = ['plugin']
126
141
 
127
142
  try {
128
143
  pluginUtils.checkDependencies.call(context, fn)
@@ -143,7 +158,7 @@ test('checkDependencies should check if the given dependency is present in the i
143
158
  }
144
159
 
145
160
  function context () {}
146
- context[pluginUtilsPublic.registeredPlugins] = []
161
+ context[pluginUtilsPublic.kRegisteredPlugins] = []
147
162
 
148
163
  try {
149
164
  pluginUtils.checkDependencies.call(context, fn)
@@ -1247,3 +1247,29 @@ test('hasPlugin returns true when using no encapsulation', async t => {
1247
1247
 
1248
1248
  await fastify.ready()
1249
1249
  })
1250
+
1251
+ test('hasPlugin returns true when using encapsulation', async t => {
1252
+ t.plan(2)
1253
+
1254
+ const fastify = Fastify()
1255
+
1256
+ const pluginCallback = function (server, options, done) {
1257
+ done()
1258
+ }
1259
+ const pluginName = 'awesome-plugin'
1260
+ const plugin = fp(pluginCallback, { name: pluginName })
1261
+
1262
+ fastify.register(plugin)
1263
+
1264
+ fastify.register(async (server) => {
1265
+ t.ok(server.hasPlugin(pluginName))
1266
+ })
1267
+
1268
+ fastify.register(async function foo (server) {
1269
+ server.register(async function bar (server) {
1270
+ t.ok(server.hasPlugin(pluginName))
1271
+ })
1272
+ })
1273
+
1274
+ await fastify.ready()
1275
+ })
@@ -0,0 +1,31 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('tap')
4
+ const fastify = require('../')
5
+ const { request, setGlobalDispatcher, Agent } = require('undici')
6
+
7
+ setGlobalDispatcher(new Agent({
8
+ keepAliveTimeout: 10,
9
+ keepAliveMaxTimeout: 10
10
+ }))
11
+
12
+ test('post empty body', async t => {
13
+ const app = fastify()
14
+ t.teardown(app.close.bind(app))
15
+
16
+ app.post('/bug', async (request, reply) => {
17
+ })
18
+
19
+ await app.listen({ port: 0 })
20
+
21
+ const res = await request(`http://127.0.0.1:${app.server.address().port}/bug`, {
22
+ method: 'POST',
23
+ headers: {
24
+ 'Content-Type': 'application/json'
25
+ },
26
+ body: JSON.stringify({ foo: 'bar' })
27
+ })
28
+
29
+ t.equal(res.statusCode, 200)
30
+ t.equal(await res.body.text(), '')
31
+ })
@@ -10,7 +10,6 @@ import fastify, {
10
10
  InjectOptions, FastifyBaseLogger,
11
11
  RawRequestDefaultExpression,
12
12
  RouteGenericInterface,
13
- ValidationResult,
14
13
  FastifyErrorCodes,
15
14
  FastifyError
16
15
  } from '../../fastify'
@@ -18,7 +17,7 @@ import { ErrorObject as AjvErrorObject } from 'ajv'
18
17
  import * as http from 'http'
19
18
  import * as https from 'https'
20
19
  import * as http2 from 'http2'
21
- import { expectType, expectError, expectAssignable } from 'tsd'
20
+ import { expectType, expectError, expectAssignable, expectNotAssignable } from 'tsd'
22
21
  import { FastifyLoggerInstance } from '../../types/logger'
23
22
  import { Socket } from 'net'
24
23
 
@@ -244,7 +243,13 @@ const ajvErrorObject: AjvErrorObject = {
244
243
  params: {},
245
244
  message: ''
246
245
  }
247
- expectAssignable<ValidationResult>(ajvErrorObject)
246
+ expectNotAssignable<AjvErrorObject>({
247
+ keyword: '',
248
+ instancePath: '',
249
+ schemaPath: '',
250
+ params: '',
251
+ message: ''
252
+ })
248
253
 
249
254
  expectAssignable<FastifyError['validation']>([ajvErrorObject])
250
255
  expectAssignable<FastifyError['validationContext']>('body')
@@ -392,3 +392,16 @@ server.addHook('preClose', function (done) {
392
392
  server.addHook('preClose', async function () {
393
393
  expectType<FastifyInstance>(this)
394
394
  })
395
+
396
+ expectError(server.addHook('onClose', async function (instance, done) {}))
397
+ expectError(server.addHook('onError', async function (request, reply, error, done) {}))
398
+ expectError(server.addHook('onReady', async function (done) {}))
399
+ expectError(server.addHook('onRequest', async function (request, reply, done) {}))
400
+ expectError(server.addHook('onRequestAbort', async function (request, done) {}))
401
+ expectError(server.addHook('onResponse', async function (request, reply, done) {}))
402
+ expectError(server.addHook('onSend', async function (request, reply, payload, done) {}))
403
+ expectError(server.addHook('onTimeout', async function (request, reply, done) {}))
404
+ expectError(server.addHook('preClose', async function (done) {}))
405
+ expectError(server.addHook('preHandler', async function (request, reply, done) {}))
406
+ expectError(server.addHook('preSerialization', async function (request, reply, payload, done) {}))
407
+ expectError(server.addHook('preValidation', async function (request, reply, done) {}))
@@ -6,7 +6,8 @@ import fastify, {
6
6
  FastifyInstance,
7
7
  RawReplyDefaultExpression,
8
8
  RawRequestDefaultExpression,
9
- RawServerDefault
9
+ RawServerDefault,
10
+ RouteGenericInterface
10
11
  } from '../../fastify'
11
12
  import { HookHandlerDoneFunction } from '../../types/hooks'
12
13
  import { FastifyReply } from '../../types/reply'
@@ -257,9 +258,13 @@ expectNotDeprecated(server.listen({ port: 3000, host: '::/0', ipv6Only: true },
257
258
 
258
259
  expectAssignable<void>(server.routing({} as RawRequestDefaultExpression, {} as RawReplyDefaultExpression))
259
260
 
260
- expectType<FastifyInstance>(fastify().get('/', {
261
+ expectType<FastifyInstance>(fastify().get<RouteGenericInterface, { contextKey: string }>('/', {
261
262
  handler: () => {},
262
263
  errorHandler: (error, request, reply) => {
264
+ expectAssignable<FastifyError>(error)
265
+ expectAssignable<FastifyRequest>(request)
266
+ expectAssignable<{ contextKey: string }>(request.routeConfig)
267
+ expectAssignable<FastifyReply>(reply)
263
268
  expectAssignable<void>(server.errorHandler(error, request, reply))
264
269
  }
265
270
  }))
@@ -83,7 +83,7 @@ const getHandler: RouteHandler = function (request, _reply) {
83
83
  request.headers = {}
84
84
 
85
85
  expectType<RequestQuerystringDefault>(request.query)
86
- expectType<any>(request.id)
86
+ expectType<string>(request.id)
87
87
  expectType<FastifyLoggerInstance>(request.log)
88
88
  expectType<RawRequestDefaultExpression['socket']>(request.socket)
89
89
  expectType<Error & { validation: any; validationContext: string } | undefined>(request.validationError)
@@ -3,7 +3,8 @@ import fastify, {
3
3
  HookHandlerDoneFunction,
4
4
  FastifyRequest,
5
5
  FastifyReply,
6
- FastifyInstance
6
+ FastifyInstance,
7
+ FastifyError
7
8
  } from '../../fastify'
8
9
  import { expectAssignable, expectError, expectType } from 'tsd'
9
10
  import { IncomingHttpHeaders } from 'http'
@@ -79,6 +80,14 @@ expectAssignable(server.withTypeProvider<TypeBoxProvider>().get(
79
80
  y: Type.Number(),
80
81
  z: Type.Number()
81
82
  })
83
+ },
84
+ errorHandler: (error, request, reply) => {
85
+ expectType<FastifyError>(error)
86
+ expectAssignable<FastifyRequest>(request)
87
+ expectType<number>(request.body.x)
88
+ expectType<number>(request.body.y)
89
+ expectType<number>(request.body.z)
90
+ expectAssignable<FastifyReply>(reply)
82
91
  }
83
92
  },
84
93
  (req) => {
@@ -108,6 +117,14 @@ expectAssignable(server.withTypeProvider<JsonSchemaToTsProvider>().get(
108
117
  z: { type: 'boolean' }
109
118
  }
110
119
  } as const
120
+ },
121
+ errorHandler: (error, request, reply) => {
122
+ expectType<FastifyError>(error)
123
+ expectAssignable<FastifyRequest>(request)
124
+ expectType<number | undefined>(request.body.x)
125
+ expectType<string | undefined>(request.body.y)
126
+ expectType<boolean | undefined>(request.body.z)
127
+ expectAssignable<FastifyReply>(reply)
111
128
  }
112
129
  },
113
130
  (req) => {
@@ -135,6 +152,14 @@ expectAssignable(server.withTypeProvider<TypeBoxProvider>().withTypeProvider<Jso
135
152
  z: { type: 'boolean' }
136
153
  }
137
154
  } as const
155
+ },
156
+ errorHandler: (error, request, reply) => {
157
+ expectType<FastifyError>(error)
158
+ expectAssignable<FastifyRequest>(request)
159
+ expectType<number | undefined>(request.body.x)
160
+ expectType<string | undefined>(request.body.y)
161
+ expectType<boolean | undefined>(request.body.z)
162
+ expectAssignable<FastifyReply>(reply)
138
163
  }
139
164
  },
140
165
  (req) => {
package/types/hooks.d.ts CHANGED
@@ -190,7 +190,7 @@ interface DoneFuncWithErrOrRes {
190
190
  * Note: the hook is NOT called if the payload is a string, a Buffer, a stream or null.
191
191
  */
192
192
  export interface preSerializationHookHandler<
193
- PreSerializationPayload,
193
+ PreSerializationPayload = unknown,
194
194
  RawServer extends RawServerBase = RawServerDefault,
195
195
  RawRequest extends RawRequestDefaultExpression<RawServer> = RawRequestDefaultExpression<RawServer>,
196
196
  RawReply extends RawReplyDefaultExpression<RawServer> = RawReplyDefaultExpression<RawServer>,
@@ -210,7 +210,7 @@ export interface preSerializationHookHandler<
210
210
  }
211
211
 
212
212
  export interface preSerializationAsyncHookHandler<
213
- PreSerializationPayload,
213
+ PreSerializationPayload = unknown,
214
214
  RawServer extends RawServerBase = RawServerDefault,
215
215
  RawRequest extends RawRequestDefaultExpression<RawServer> = RawRequestDefaultExpression<RawServer>,
216
216
  RawReply extends RawReplyDefaultExpression<RawServer> = RawReplyDefaultExpression<RawServer>,
@@ -233,7 +233,7 @@ export interface preSerializationAsyncHookHandler<
233
233
  * Note: If you change the payload, you may only change it to a string, a Buffer, a stream, or null.
234
234
  */
235
235
  export interface onSendHookHandler<
236
- OnSendPayload,
236
+ OnSendPayload = unknown,
237
237
  RawServer extends RawServerBase = RawServerDefault,
238
238
  RawRequest extends RawRequestDefaultExpression<RawServer> = RawRequestDefaultExpression<RawServer>,
239
239
  RawReply extends RawReplyDefaultExpression<RawServer> = RawReplyDefaultExpression<RawServer>,
@@ -253,7 +253,7 @@ export interface onSendHookHandler<
253
253
  }
254
254
 
255
255
  export interface onSendAsyncHookHandler<
256
- OnSendPayload,
256
+ OnSendPayload = unknown,
257
257
  RawServer extends RawServerBase = RawServerDefault,
258
258
  RawRequest extends RawRequestDefaultExpression<RawServer> = RawRequestDefaultExpression<RawServer>,
259
259
  RawReply extends RawReplyDefaultExpression<RawServer> = RawReplyDefaultExpression<RawServer>,
@@ -432,6 +432,66 @@ export interface onRequestAbortAsyncHookHandler<
432
432
  ): Promise<unknown>;
433
433
  }
434
434
 
435
+ export type LifecycleHook = 'onRequest'
436
+ | 'preParsing'
437
+ | 'preValidation'
438
+ | 'preHandler'
439
+ | 'preSerialization'
440
+ | 'onSend'
441
+ | 'onResponse'
442
+ | 'onRequest'
443
+ | 'onError'
444
+ | 'onTimeout'
445
+ | 'onRequestAbort'
446
+
447
+ export type LifecycleHookLookup<K extends LifecycleHook> = K extends 'onRequest'
448
+ ? onRequestHookHandler
449
+ : K extends 'preParsing'
450
+ ? preParsingHookHandler
451
+ : K extends 'preValidation'
452
+ ? preValidationHookHandler
453
+ : K extends 'preHandler'
454
+ ? preHandlerHookHandler
455
+ : K extends 'preSerialization'
456
+ ? preSerializationHookHandler
457
+ : K extends 'onSend'
458
+ ? onSendHookHandler
459
+ : K extends 'onResponse'
460
+ ? onResponseHookHandler
461
+ : K extends 'onRequest'
462
+ ? onRequestHookHandler
463
+ : K extends 'onError'
464
+ ? onErrorHookHandler
465
+ : K extends 'onTimeout'
466
+ ? onTimeoutHookHandler
467
+ : K extends 'onRequestAbort'
468
+ ? onRequestAbortHookHandler
469
+ : never
470
+
471
+ export type LifecycleHookAsyncLookup<K extends LifecycleHook> = K extends 'onRequest'
472
+ ? onRequestAsyncHookHandler
473
+ : K extends 'preParsing'
474
+ ? preParsingAsyncHookHandler
475
+ : K extends 'preValidation'
476
+ ? preValidationAsyncHookHandler
477
+ : K extends 'preHandler'
478
+ ? preHandlerAsyncHookHandler
479
+ : K extends 'preSerialization'
480
+ ? preSerializationAsyncHookHandler
481
+ : K extends 'onSend'
482
+ ? onSendAsyncHookHandler
483
+ : K extends 'onResponse'
484
+ ? onResponseAsyncHookHandler
485
+ : K extends 'onRequest'
486
+ ? onRequestAsyncHookHandler
487
+ : K extends 'onError'
488
+ ? onErrorAsyncHookHandler
489
+ : K extends 'onTimeout'
490
+ ? onTimeoutAsyncHookHandler
491
+ : K extends 'onRequestAbort'
492
+ ? onRequestAbortAsyncHookHandler
493
+ : never
494
+
435
495
  // Application Hooks
436
496
 
437
497
  /**
@@ -555,3 +615,43 @@ export interface preCloseAsyncHookHandler<
555
615
  this: FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider>,
556
616
  ): Promise<unknown>;
557
617
  }
618
+
619
+ export type ApplicationHook = 'onRoute'
620
+ | 'onRegister'
621
+ | 'onReady'
622
+ | 'onClose'
623
+ | 'preClose'
624
+
625
+ export type ApplicationHookLookup<K extends ApplicationHook> = K extends 'onRegister'
626
+ ? onRegisterHookHandler
627
+ : K extends 'onReady'
628
+ ? onReadyHookHandler
629
+ : K extends 'onClose'
630
+ ? onCloseHookHandler
631
+ : K extends 'preClose'
632
+ ? preCloseHookHandler
633
+ : K extends 'onRoute'
634
+ ? onRouteHookHandler
635
+ : never
636
+
637
+ export type ApplicationHookAsyncLookup<K extends ApplicationHook> = K extends 'onRegister'
638
+ ? onRegisterHookHandler
639
+ : K extends 'onReady'
640
+ ? onReadyAsyncHookHandler
641
+ : K extends 'onClose'
642
+ ? onCloseAsyncHookHandler
643
+ : K extends 'preClose'
644
+ ? preCloseAsyncHookHandler
645
+ : never
646
+
647
+ export type HookLookup <K extends ApplicationHook | LifecycleHook> = K extends ApplicationHook
648
+ ? ApplicationHookLookup<K>
649
+ : K extends LifecycleHook
650
+ ? LifecycleHookLookup<K>
651
+ : never
652
+
653
+ export type HookAsyncLookup <K extends ApplicationHook | LifecycleHook> = K extends ApplicationHook
654
+ ? ApplicationHookAsyncLookup<K>
655
+ : K extends LifecycleHook
656
+ ? LifecycleHookAsyncLookup<K>
657
+ : never