fastify 4.24.3 → 4.25.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 (59) hide show
  1. package/README.md +10 -5
  2. package/SECURITY.md +27 -0
  3. package/docs/Guides/Ecosystem.md +18 -6
  4. package/docs/Guides/Getting-Started.md +3 -3
  5. package/docs/Guides/Plugins-Guide.md +2 -2
  6. package/docs/Guides/Style-Guide.md +7 -7
  7. package/docs/Reference/ContentTypeParser.md +2 -0
  8. package/docs/Reference/Errors.md +171 -397
  9. package/docs/Reference/Hooks.md +8 -2
  10. package/docs/Reference/Index.md +2 -0
  11. package/docs/Reference/Reply.md +16 -5
  12. package/docs/Reference/Request.md +1 -1
  13. package/docs/Reference/Routes.md +5 -5
  14. package/docs/Reference/TypeScript.md +1 -1
  15. package/docs/Reference/Warnings.md +77 -0
  16. package/fastify.js +37 -20
  17. package/lib/decorate.js +2 -2
  18. package/lib/errors.js +1 -1
  19. package/lib/hooks.js +1 -1
  20. package/lib/pluginUtils.js +10 -1
  21. package/lib/reply.js +5 -5
  22. package/lib/request.js +14 -7
  23. package/lib/route.js +9 -5
  24. package/lib/server.js +20 -27
  25. package/lib/validation.js +5 -5
  26. package/lib/warnings.js +110 -40
  27. package/package.json +3 -3
  28. package/test/close-pipelining.test.js +4 -4
  29. package/test/close.test.js +3 -3
  30. package/test/constrained-routes.test.js +24 -24
  31. package/test/decorator.test.js +27 -22
  32. package/test/default-route.test.js +7 -7
  33. package/test/fastify-instance.test.js +120 -0
  34. package/test/hooks.on-ready.test.js +16 -0
  35. package/test/hooks.test.js +1 -3
  36. package/test/http2/constraint.test.js +1 -1
  37. package/test/internals/errors.test.js +28 -3
  38. package/test/internals/reply.test.js +33 -9
  39. package/test/logger/instantiation.test.js +2 -1
  40. package/test/plugin.4.test.js +47 -0
  41. package/test/register.test.js +5 -5
  42. package/test/reply-trailers.test.js +1 -1
  43. package/test/route.7.test.js +7 -6
  44. package/test/schema-examples.test.js +2 -2
  45. package/test/schema-feature.test.js +11 -11
  46. package/test/server.test.js +51 -0
  47. package/test/types/hooks.test-d.ts +124 -1
  48. package/test/types/instance.test-d.ts +12 -0
  49. package/test/types/logger.test-d.ts +14 -0
  50. package/test/types/reply.test-d.ts +25 -6
  51. package/test/types/request.test-d.ts +3 -2
  52. package/test/types/route.test-d.ts +31 -0
  53. package/test/versioned-routes.test.js +7 -6
  54. package/types/hooks.d.ts +183 -0
  55. package/types/instance.d.ts +12 -12
  56. package/types/reply.d.ts +7 -10
  57. package/types/request.d.ts +2 -1
  58. package/types/route.d.ts +37 -26
  59. package/types/utils.d.ts +10 -0
@@ -35,6 +35,22 @@ t.test('onReady should be called in order', t => {
35
35
  fastify.ready(err => t.error(err))
36
36
  })
37
37
 
38
+ t.test('onReady should be called once', async (t) => {
39
+ const app = Fastify()
40
+ let counter = 0
41
+
42
+ app.addHook('onReady', async function () {
43
+ counter++
44
+ })
45
+
46
+ const promises = [1, 2, 3, 4, 5].map((id) => app.ready().then(() => id))
47
+
48
+ const result = await Promise.race(promises)
49
+
50
+ t.strictSame(result, 1, 'Should resolve in order')
51
+ t.equal(counter, 1, 'Should call onReady only once')
52
+ })
53
+
38
54
  t.test('async onReady should be called in order', async t => {
39
55
  t.plan(7)
40
56
  const fastify = Fastify()
@@ -3469,7 +3469,7 @@ test('onRequestAbort should support encapsulation', t => {
3469
3469
  done()
3470
3470
  })
3471
3471
 
3472
- fastify.register(async function (_child, _, done) {
3472
+ fastify.register(async function (_child, _) {
3473
3473
  child = _child
3474
3474
 
3475
3475
  fastify.addHook('onRequestAbort', async function (req) {
@@ -3488,8 +3488,6 @@ test('onRequestAbort should support encapsulation', t => {
3488
3488
  t.equal(++order, 3, 'called in route')
3489
3489
  }
3490
3490
  })
3491
-
3492
- done()
3493
3491
  })
3494
3492
 
3495
3493
  fastify.listen({ port: 0 }, err => {
@@ -28,7 +28,7 @@ test('A route supports host constraints under http2 protocol and secure connecti
28
28
  t.fail('Key/cert loading failed', e)
29
29
  }
30
30
 
31
- const constrain = 'fastify.io'
31
+ const constrain = 'fastify.dev'
32
32
 
33
33
  fastify.route({
34
34
  method: 'GET',
@@ -292,7 +292,7 @@ test('FST_ERR_MISSING_MIDDLEWARE', t => {
292
292
  const error = new errors.FST_ERR_MISSING_MIDDLEWARE()
293
293
  t.equal(error.name, 'FastifyError')
294
294
  t.equal(error.code, 'FST_ERR_MISSING_MIDDLEWARE')
295
- t.equal(error.message, 'You must register a plugin for handling middlewares, visit fastify.io/docs/latest/Reference/Middleware/ for more info.')
295
+ t.equal(error.message, 'You must register a plugin for handling middlewares, visit fastify.dev/docs/latest/Reference/Middleware/ for more info.')
296
296
  t.equal(error.statusCode, 500)
297
297
  t.ok(error instanceof Error)
298
298
  })
@@ -817,6 +817,31 @@ test('FST_ERR_LISTEN_OPTIONS_INVALID', t => {
817
817
  t.ok(error instanceof TypeError)
818
818
  })
819
819
 
820
+ test('Ensure that all errors are in Errors.md TOC', t => {
821
+ t.plan(78)
822
+ const errorsMd = readFileSync(resolve(__dirname, '../../docs/Reference/Errors.md'), 'utf8')
823
+
824
+ const exportedKeys = Object.keys(errors)
825
+ for (const key of exportedKeys) {
826
+ if (errors[key].name === 'FastifyError') {
827
+ t.ok(errorsMd.includes(` - [${key.toUpperCase()}](#${key.toLowerCase()})`), key)
828
+ }
829
+ }
830
+ })
831
+
832
+ test('Ensure that non-existing errors are not in Errors.md TOC', t => {
833
+ t.plan(78)
834
+ const errorsMd = readFileSync(resolve(__dirname, '../../docs/Reference/Errors.md'), 'utf8')
835
+
836
+ const matchRE = / {4}- \[([A-Z0-9_]+)\]\(#[a-z0-9_]+\)/g
837
+ const matches = errorsMd.matchAll(matchRE)
838
+ const exportedKeys = Object.keys(errors)
839
+
840
+ for (const match of matches) {
841
+ t.ok(exportedKeys.indexOf(match[1]) !== -1, match[1])
842
+ }
843
+ })
844
+
820
845
  test('Ensure that all errors are in Errors.md documented', t => {
821
846
  t.plan(78)
822
847
  const errorsMd = readFileSync(resolve(__dirname, '../../docs/Reference/Errors.md'), 'utf8')
@@ -824,7 +849,7 @@ test('Ensure that all errors are in Errors.md documented', t => {
824
849
  const exportedKeys = Object.keys(errors)
825
850
  for (const key of exportedKeys) {
826
851
  if (errors[key].name === 'FastifyError') {
827
- t.ok(errorsMd.includes(`#### ${key}\n`), key)
852
+ t.ok(errorsMd.includes(`<a id="${key.toLowerCase()}">${key.toUpperCase()}</a>`), key)
828
853
  }
829
854
  }
830
855
  })
@@ -833,7 +858,7 @@ test('Ensure that non-existing errors are not in Errors.md documented', t => {
833
858
  t.plan(78)
834
859
  const errorsMd = readFileSync(resolve(__dirname, '../../docs/Reference/Errors.md'), 'utf8')
835
860
 
836
- const matchRE = /#### ([0-9a-zA-Z_]+)\n/g
861
+ const matchRE = /<a id="[0-9a-zA-Z_]+">([0-9a-zA-Z_]+)<\/a>/g
837
862
  const matches = errorsMd.matchAll(matchRE)
838
863
  const exportedKeys = Object.keys(errors)
839
864
 
@@ -19,7 +19,7 @@ const {
19
19
  } = require('../../lib/symbols')
20
20
  const fs = require('node:fs')
21
21
  const path = require('node:path')
22
- const warning = require('../../lib/warnings')
22
+ const { FSTDEP019, FSTDEP010 } = require('../../lib/warnings')
23
23
 
24
24
  const agent = new http.Agent({ keepAlive: false })
25
25
 
@@ -1466,14 +1466,13 @@ test('should emit deprecation warning when trying to modify the reply.sent prope
1466
1466
  t.plan(4)
1467
1467
  const fastify = Fastify()
1468
1468
 
1469
- const deprecationCode = 'FSTDEP010'
1470
- warning.emitted.delete(deprecationCode)
1469
+ FSTDEP010.emitted = false
1471
1470
 
1472
1471
  process.removeAllListeners('warning')
1473
1472
  process.on('warning', onWarning)
1474
1473
  function onWarning (warning) {
1475
- t.equal(warning.name, 'FastifyDeprecation')
1476
- t.equal(warning.code, deprecationCode)
1474
+ t.equal(warning.name, 'DeprecationWarning')
1475
+ t.equal(warning.code, FSTDEP010.code)
1477
1476
  }
1478
1477
 
1479
1478
  fastify.get('/', (req, reply) => {
@@ -1494,14 +1493,13 @@ test('should emit deprecation warning when trying to use the reply.context.confi
1494
1493
  t.plan(4)
1495
1494
  const fastify = Fastify()
1496
1495
 
1497
- const deprecationCode = 'FSTDEP019'
1498
- warning.emitted.delete(deprecationCode)
1496
+ FSTDEP019.emitted = false
1499
1497
 
1500
1498
  process.removeAllListeners('warning')
1501
1499
  process.on('warning', onWarning)
1502
1500
  function onWarning (warning) {
1503
- t.equal(warning.name, 'FastifyDeprecation')
1504
- t.equal(warning.code, deprecationCode)
1501
+ t.equal(warning.name, 'DeprecationWarning')
1502
+ t.equal(warning.code, FSTDEP019.code)
1505
1503
  }
1506
1504
 
1507
1505
  fastify.get('/', (req, reply) => {
@@ -2148,3 +2146,29 @@ test('reply.send will intercept ERR_HTTP_HEADERS_SENT and log an error message',
2148
2146
  t.equal(err.code, 'ERR_HTTP_HEADERS_SENT')
2149
2147
  }
2150
2148
  })
2149
+
2150
+ test('Uint8Array view of ArrayBuffer returns correct byteLength', t => {
2151
+ t.plan(5)
2152
+ const fastify = Fastify()
2153
+
2154
+ const arrBuf = new ArrayBuffer(100)
2155
+ const arrView = new Uint8Array(arrBuf, 0, 10)
2156
+ fastify.get('/', function (req, reply) {
2157
+ return reply.send(arrView)
2158
+ })
2159
+
2160
+ fastify.listen({ port: 0 }, err => {
2161
+ t.error(err)
2162
+ t.teardown(fastify.close.bind(fastify))
2163
+
2164
+ fastify.inject({
2165
+ method: 'GET',
2166
+ url: '/'
2167
+ }, (err, response) => {
2168
+ t.error(err)
2169
+ t.equal(response.headers['content-type'], 'application/octet-stream')
2170
+ t.equal(response.headers['content-length'], '10')
2171
+ t.same(response.rawPayload.byteLength, arrView.byteLength)
2172
+ })
2173
+ })
2174
+ })
@@ -151,7 +151,8 @@ t.test('logger instantiation', (t) => {
151
151
  ]
152
152
 
153
153
  const { file, cleanup } = createTempFile(t)
154
- if (process.env.CITGM) { fs.writeFileSync(file, '') }
154
+ // 0600 permissions (read/write for owner only)
155
+ if (process.env.CITGM) { fs.writeFileSync(file, '', { mode: 0o600 }) }
155
156
 
156
157
  const fastify = Fastify({
157
158
  logger: { file }
@@ -414,3 +414,50 @@ test('hasPlugin returns true when using encapsulation', async t => {
414
414
 
415
415
  await fastify.ready()
416
416
  })
417
+
418
+ test('registering plugins with mixed style should return a warning', async t => {
419
+ t.plan(12)
420
+
421
+ const pluginNames = ['error-plugin', 'anonymous', 'anotherPlugin', 'anotherPluginNamed']
422
+
423
+ const oldWarnings = process.listeners('warning')
424
+ process.removeAllListeners('warning')
425
+ process.on('warning', onWarning)
426
+ function onWarning (warning) {
427
+ t.match(warning.message, new RegExp(`.*${pluginNames.shift()} plugin being registered mixes async and callback styles.*`))
428
+ t.equal(warning.name, 'FastifyWarning')
429
+ t.equal(warning.code, 'FSTWRN002')
430
+ }
431
+ t.teardown(() => {
432
+ process.removeListener('warning', onWarning)
433
+ for (const warning of oldWarnings) {
434
+ process.on('warning', warning)
435
+ }
436
+ })
437
+
438
+ const fastify = Fastify()
439
+
440
+ const pluginName = 'error-plugin'
441
+ const errorPlugin = async (app, opts, done) => {
442
+ done()
443
+ }
444
+
445
+ const namedPlugin = fp(errorPlugin, { name: pluginName })
446
+
447
+ async function anotherPlugin (app, opts, done) {
448
+ done()
449
+ }
450
+
451
+ const anotherPluginNamed = async function (app, opts, done) {
452
+ done()
453
+ }
454
+
455
+ fastify.register(namedPlugin)
456
+ fastify.register(async (app, opts, done) => {
457
+ done()
458
+ })
459
+ fastify.register(anotherPlugin)
460
+ fastify.register(anotherPluginNamed)
461
+
462
+ await fastify.ready()
463
+ })
@@ -105,20 +105,20 @@ test('awaitable register and after', async t => {
105
105
  let second = false
106
106
  let third = false
107
107
 
108
- await fastify.register(async (instance, opts, done) => {
108
+ await fastify.register(async (instance, opts) => {
109
109
  first = true
110
110
  })
111
111
 
112
112
  t.equal(first, true)
113
113
 
114
- fastify.register(async (instance, opts, done) => {
114
+ fastify.register(async (instance, opts) => {
115
115
  second = true
116
116
  })
117
117
 
118
118
  await fastify.after()
119
119
  t.equal(second, true)
120
120
 
121
- fastify.register(async (instance, opts, done) => {
121
+ fastify.register(async (instance, opts) => {
122
122
  third = true
123
123
  })
124
124
 
@@ -145,7 +145,7 @@ test('awaitable register error handling', async t => {
145
145
 
146
146
  await t.rejects(fastify.after(), e)
147
147
 
148
- fastify.register(async (instance, opts, done) => {
148
+ fastify.register(async (instance, opts) => {
149
149
  t.fail('should not be executed')
150
150
  })
151
151
 
@@ -167,7 +167,7 @@ test('awaitable after error handling', async t => {
167
167
 
168
168
  await t.rejects(fastify.after(), e)
169
169
 
170
- fastify.register(async (instance, opts, done) => {
170
+ fastify.register(async (instance, opts) => {
171
171
  t.fail('should not be executed')
172
172
  })
173
173
 
@@ -200,7 +200,7 @@ test('should emit deprecation warning when using direct return', t => {
200
200
 
201
201
  process.on('warning', onWarning)
202
202
  function onWarning (warning) {
203
- t.equal(warning.name, 'FastifyDeprecation')
203
+ t.equal(warning.name, 'DeprecationWarning')
204
204
  t.equal(warning.code, 'FSTDEP013')
205
205
  }
206
206
  t.teardown(() => process.removeListener('warning', onWarning))
@@ -178,14 +178,15 @@ test('Set a custom HEAD route before GET one without disabling exposeHeadRoutes
178
178
  test('Set a custom HEAD route before GET one without disabling exposeHeadRoutes (route)', t => {
179
179
  t.plan(7)
180
180
 
181
- function onWarning (code) {
182
- t.equal(code, 'FSTDEP007')
183
- }
184
- const warning = {
185
- emit: onWarning
181
+ function onWarning () {
182
+ t.pass('warning emitted')
186
183
  }
187
184
 
188
- const route = proxyquire('../lib/route', { './warnings': warning })
185
+ const route = proxyquire('../lib/route', {
186
+ './warnings': {
187
+ FSTDEP007: onWarning
188
+ }
189
+ })
189
190
  const fastify = proxyquire('..', { './lib/route.js': route })()
190
191
 
191
192
  const resBuffer = Buffer.from('I am a coffee!')
@@ -540,7 +540,7 @@ test('should be able to handle formats of ajv-formats when added by plugins opti
540
540
  method: 'POST',
541
541
  payload: {
542
542
  id: '254381a5-888c-4b41-8116-e3b1a54980bd',
543
- email: 'info@fastify.io'
543
+ email: 'info@fastify.dev'
544
544
  },
545
545
  url: '/'
546
546
  }, (_err, res) => {
@@ -552,7 +552,7 @@ test('should be able to handle formats of ajv-formats when added by plugins opti
552
552
  method: 'POST',
553
553
  payload: {
554
554
  id: 'invalid',
555
- email: 'info@fastify.io'
555
+ email: 'info@fastify.dev'
556
556
  },
557
557
  url: '/'
558
558
  }, (_err, res) => {
@@ -6,7 +6,7 @@ const fp = require('fastify-plugin')
6
6
  const deepClone = require('rfdc')({ circles: true, proto: false })
7
7
  const Ajv = require('ajv')
8
8
  const { kSchemaController } = require('../lib/symbols.js')
9
- const warning = require('../lib/warnings')
9
+ const { FSTWRN001 } = require('../lib/warnings')
10
10
 
11
11
  const echoParams = (req, reply) => { reply.send(req.params) }
12
12
  const echoBody = (req, reply) => { reply.send(req.body) }
@@ -261,12 +261,12 @@ test('Should emit warning if the schema headers is undefined', t => {
261
261
  process.on('warning', onWarning)
262
262
  function onWarning (warning) {
263
263
  t.equal(warning.name, 'FastifyWarning')
264
- t.equal(warning.code, 'FSTWRN001')
264
+ t.equal(warning.code, FSTWRN001.code)
265
265
  }
266
266
 
267
267
  t.teardown(() => {
268
268
  process.removeListener('warning', onWarning)
269
- warning.emitted.set('FSTWRN001', false)
269
+ FSTWRN001.emitted = false
270
270
  })
271
271
 
272
272
  fastify.post('/:id', {
@@ -292,12 +292,12 @@ test('Should emit warning if the schema body is undefined', t => {
292
292
  process.on('warning', onWarning)
293
293
  function onWarning (warning) {
294
294
  t.equal(warning.name, 'FastifyWarning')
295
- t.equal(warning.code, 'FSTWRN001')
295
+ t.equal(warning.code, FSTWRN001.code)
296
296
  }
297
297
 
298
298
  t.teardown(() => {
299
299
  process.removeListener('warning', onWarning)
300
- warning.emitted.set('FSTWRN001', false)
300
+ FSTWRN001.emitted = false
301
301
  })
302
302
 
303
303
  fastify.post('/:id', {
@@ -323,12 +323,12 @@ test('Should emit warning if the schema query is undefined', t => {
323
323
  process.on('warning', onWarning)
324
324
  function onWarning (warning) {
325
325
  t.equal(warning.name, 'FastifyWarning')
326
- t.equal(warning.code, 'FSTWRN001')
326
+ t.equal(warning.code, FSTWRN001.code)
327
327
  }
328
328
 
329
329
  t.teardown(() => {
330
330
  process.removeListener('warning', onWarning)
331
- warning.emitted.set('FSTWRN001', false)
331
+ FSTWRN001.emitted = false
332
332
  })
333
333
 
334
334
  fastify.post('/:id', {
@@ -354,12 +354,12 @@ test('Should emit warning if the schema params is undefined', t => {
354
354
  process.on('warning', onWarning)
355
355
  function onWarning (warning) {
356
356
  t.equal(warning.name, 'FastifyWarning')
357
- t.equal(warning.code, 'FSTWRN001')
357
+ t.equal(warning.code, FSTWRN001.code)
358
358
  }
359
359
 
360
360
  t.teardown(() => {
361
361
  process.removeListener('warning', onWarning)
362
- warning.emitted.set('FSTWRN001', false)
362
+ FSTWRN001.emitted = false
363
363
  })
364
364
 
365
365
  fastify.post('/:id', {
@@ -390,14 +390,14 @@ test('Should emit a warning for every route with undefined schema', t => {
390
390
  // => 3 x 4 assertions = 12 assertions
391
391
  function onWarning (warning) {
392
392
  t.equal(warning.name, 'FastifyWarning')
393
- t.equal(warning.code, 'FSTWRN001')
393
+ t.equal(warning.code, FSTWRN001.code)
394
394
  t.equal(runs++, expectedWarningEmitted.shift())
395
395
  }
396
396
 
397
397
  process.on('warning', onWarning)
398
398
  t.teardown(() => {
399
399
  process.removeListener('warning', onWarning)
400
- warning.emitted.set('FSTWRN001', false)
400
+ FSTWRN001.emitted = false
401
401
  })
402
402
 
403
403
  fastify.get('/undefinedParams/:id', {
@@ -4,6 +4,7 @@ const t = require('tap')
4
4
  const test = t.test
5
5
  const Fastify = require('..')
6
6
  const semver = require('semver')
7
+ const undici = require('undici')
7
8
 
8
9
  test('listen should accept null port', t => {
9
10
  t.plan(1)
@@ -123,3 +124,53 @@ test('abort signal', { skip: semver.lt(process.version, '16.0.0') }, t => {
123
124
 
124
125
  t.end()
125
126
  })
127
+
128
+ t.test('#5180 - preClose should be called before closing secondary server', t => {
129
+ t.plan(2)
130
+ const fastify = Fastify({ forceCloseConnections: true })
131
+ let flag = false
132
+ t.teardown(fastify.close.bind(fastify))
133
+
134
+ fastify.addHook('preClose', async () => {
135
+ flag = true
136
+ })
137
+
138
+ fastify.get('/', async (req, reply) => {
139
+ await new Promise((resolve) => {
140
+ setTimeout(() => resolve(1), 1000)
141
+ })
142
+
143
+ return { hello: 'world' }
144
+ })
145
+
146
+ fastify.listen({ port: 0 }, (err) => {
147
+ t.error(err)
148
+ const addresses = fastify.addresses()
149
+ const mainServerAddress = fastify.server.address()
150
+ let secondaryAddress
151
+ for (const addr of addresses) {
152
+ if (addr.family !== mainServerAddress.family) {
153
+ secondaryAddress = addr
154
+ secondaryAddress.address = secondaryAddress.family === 'IPv6'
155
+ ? `[${secondaryAddress.address}]`
156
+ : secondaryAddress.address
157
+ break
158
+ }
159
+ }
160
+
161
+ if (!secondaryAddress) {
162
+ t.pass('no secondary server')
163
+ return
164
+ }
165
+
166
+ undici.request(`http://${secondaryAddress.address}:${secondaryAddress.port}/`)
167
+ .then(
168
+ () => { t.fail('Request should not succeed') },
169
+ () => { t.ok(flag) }
170
+ )
171
+
172
+ setTimeout(() => {
173
+ fastify.close()
174
+ }, 250)
175
+ })
176
+ })
@@ -14,7 +14,7 @@ import fastify, {
14
14
  RegisterOptions,
15
15
  RouteOptions
16
16
  } from '../../fastify'
17
- import { RequestPayload, preHandlerAsyncHookHandler } from '../../types/hooks'
17
+ import { DoneFuncWithErrOrRes, HookHandlerDoneFunction, RequestPayload, preHandlerAsyncHookHandler } from '../../types/hooks'
18
18
  import { FastifyRouteConfig, RouteGenericInterface } from '../../types/route'
19
19
 
20
20
  const server = fastify()
@@ -392,6 +392,129 @@ server.route<RouteGenericInterface, CustomContextConfig>({
392
392
  }
393
393
  })
394
394
 
395
+ server.route({
396
+ method: 'GET',
397
+ url: '/',
398
+ handler: (request, reply) => {
399
+ expectType<FastifyRequest>(request)
400
+ expectType<FastifyReply>(reply)
401
+ },
402
+ onRequest: (request, reply, done) => {
403
+ expectType<FastifyRequest>(request)
404
+ expectType<FastifyReply>(reply)
405
+ expectType<HookHandlerDoneFunction>(done)
406
+ },
407
+ onRequestAbort: (request, done) => {
408
+ expectType<FastifyRequest>(request)
409
+ expectType<HookHandlerDoneFunction>(done)
410
+ },
411
+ preParsing: (request, reply, payload, done) => {
412
+ expectType<FastifyRequest>(request)
413
+ expectType<FastifyReply>(reply)
414
+ expectType<RequestPayload>(payload)
415
+ expectType<<TError extends Error = FastifyError>(err?: TError | null | undefined, res?: RequestPayload | undefined) => void>(done)
416
+ },
417
+ preValidation: (request, reply, done) => {
418
+ expectType<FastifyRequest>(request)
419
+ expectType<FastifyReply>(reply)
420
+ expectType<HookHandlerDoneFunction>(done)
421
+ },
422
+ preHandler: (request, reply, done) => {
423
+ expectType<FastifyRequest>(request)
424
+ expectType<FastifyReply>(reply)
425
+ expectType<HookHandlerDoneFunction>(done)
426
+ },
427
+ preSerialization: (request, reply, payload, done) => {
428
+ expectType<FastifyRequest>(request)
429
+ expectType<FastifyReply>(reply)
430
+ expectType<unknown>(payload)
431
+ expectType<DoneFuncWithErrOrRes>(done)
432
+ },
433
+ onSend: (request, reply, payload, done) => {
434
+ expectType<FastifyRequest>(request)
435
+ expectType<FastifyReply>(reply)
436
+ expectType<unknown>(payload)
437
+ expectType<DoneFuncWithErrOrRes>(done)
438
+ },
439
+ onResponse: (request, reply, done) => {
440
+ expectType<FastifyRequest>(request)
441
+ expectType<FastifyReply>(reply)
442
+ expectType<HookHandlerDoneFunction>(done)
443
+ },
444
+ onTimeout: (request, reply, done) => {
445
+ expectType<FastifyRequest>(request)
446
+ expectType<FastifyReply>(reply)
447
+ expectType<HookHandlerDoneFunction>(done)
448
+ },
449
+ onError: (request, reply, error, done) => {
450
+ expectType<FastifyRequest>(request)
451
+ expectType<FastifyReply>(reply)
452
+ expectType<FastifyError>(error)
453
+ expectType<() => void>(done)
454
+ }
455
+ })
456
+
457
+ server.get('/', {
458
+ onRequest: async (request, reply) => {
459
+ expectType<FastifyRequest>(request)
460
+ expectType<FastifyReply>(reply)
461
+ },
462
+ onRequestAbort: async (request, reply) => {
463
+ expectType<FastifyRequest>(request)
464
+ },
465
+ preParsing: async (request, reply, payload) => {
466
+ expectType<FastifyRequest>(request)
467
+ expectType<FastifyReply>(reply)
468
+ expectType<RequestPayload>(payload)
469
+ },
470
+ preValidation: async (request, reply) => {
471
+ expectType<FastifyRequest>(request)
472
+ expectType<FastifyReply>(reply)
473
+ },
474
+ preHandler: async (request, reply) => {
475
+ expectType<FastifyRequest>(request)
476
+ expectType<FastifyReply>(reply)
477
+ },
478
+ preSerialization: async (request, reply, payload) => {
479
+ expectType<FastifyRequest>(request)
480
+ expectType<FastifyReply>(reply)
481
+ expectType<unknown>(payload)
482
+ },
483
+ onSend: async (request, reply, payload) => {
484
+ expectType<FastifyRequest>(request)
485
+ expectType<FastifyReply>(reply)
486
+ expectType<unknown>(payload)
487
+ },
488
+ onResponse: async (request, reply) => {
489
+ expectType<FastifyRequest>(request)
490
+ expectType<FastifyReply>(reply)
491
+ },
492
+ onTimeout: async (request, reply) => {
493
+ expectType<FastifyRequest>(request)
494
+ expectType<FastifyReply>(reply)
495
+ },
496
+ onError: async (request, reply, error) => {
497
+ expectType<FastifyRequest>(request)
498
+ expectType<FastifyReply>(reply)
499
+ expectType<FastifyError>(error)
500
+ }
501
+ }, async (request, reply) => {
502
+ expectType<FastifyRequest>(request)
503
+ expectType<FastifyReply>(reply)
504
+ })
505
+
506
+ // TODO: Should throw errors
507
+ // expectError(server.get('/', { onRequest: async (request, reply, done) => {} }, async (request, reply) => {}))
508
+ // expectError(server.get('/', { onRequestAbort: async (request, done) => {} }, async (request, reply) => {}))
509
+ // expectError(server.get('/', { preParsing: async (request, reply, payload, done) => {} }, async (request, reply) => {}))
510
+ // expectError(server.get('/', { preValidation: async (request, reply, done) => {} }, async (request, reply) => {}))
511
+ // expectError(server.get('/', { preHandler: async (request, reply, done) => {} }, async (request, reply) => {}))
512
+ // expectError(server.get('/', { preSerialization: async (request, reply, payload, done) => {} }, async (request, reply) => {}))
513
+ // expectError(server.get('/', { onSend: async (request, reply, payload, done) => {} }, async (request, reply) => {}))
514
+ // expectError(server.get('/', { onResponse: async (request, reply, done) => {} }, async (request, reply) => {}))
515
+ // expectError(server.get('/', { onTimeout: async (request, reply, done) => {} }, async (request, reply) => {}))
516
+ // expectError(server.get('/', { onError: async (request, reply, error, done) => {} }, async (request, reply) => {}))
517
+
395
518
  server.addHook('preClose', function (done) {
396
519
  expectType<FastifyInstance>(this)
397
520
  expectAssignable<(err?: FastifyError) => void>(done)
@@ -256,6 +256,18 @@ expectNotDeprecated(server.listen({ port: 3000, host: '0.0.0.0', backlog: 42 },
256
256
  expectNotDeprecated(server.listen({ port: 3000, host: '0.0.0.0', backlog: 42, exclusive: true }, () => {}))
257
257
  expectNotDeprecated(server.listen({ port: 3000, host: '::/0', ipv6Only: true }, () => {}))
258
258
 
259
+ // test after method
260
+ expectAssignable<FastifyInstance>(server.after())
261
+ expectAssignable<FastifyInstance>(server.after((err) => {
262
+ expectType<Error | null>(err)
263
+ }))
264
+
265
+ // test ready method
266
+ expectAssignable<FastifyInstance>(server.ready())
267
+ expectAssignable<FastifyInstance>(server.ready((err) => {
268
+ expectType<Error | null>(err)
269
+ }))
270
+
259
271
  expectAssignable<void>(server.routing({} as RawRequestDefaultExpression, {} as RawReplyDefaultExpression))
260
272
 
261
273
  expectType<FastifyInstance>(fastify().get<RouteGenericInterface, { contextKey: string }>('/', {
@@ -74,6 +74,20 @@ P.Logger
74
74
 
75
75
  expectType<P.Logger>(serverWithPino.log)
76
76
 
77
+ serverWithPino.route({
78
+ method: 'GET',
79
+ url: '/',
80
+ handler (request) {
81
+ expectType<P.Logger>(this.log)
82
+ expectType<P.Logger>(request.log)
83
+ }
84
+ })
85
+
86
+ serverWithPino.get('/', function (request) {
87
+ expectType<P.Logger>(this.log)
88
+ expectType<P.Logger>(request.log)
89
+ })
90
+
77
91
  const serverWithLogOptions = fastify<
78
92
  Server,
79
93
  IncomingMessage,