fastify 3.9.2 → 3.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/GOVERNANCE.md +1 -1
  2. package/README.md +12 -8
  3. package/SECURITY.md +3 -3
  4. package/docs/ContentTypeParser.md +1 -1
  5. package/docs/Ecosystem.md +16 -6
  6. package/docs/Encapsulation.md +5 -2
  7. package/docs/Fluent-Schema.md +4 -4
  8. package/docs/Getting-Started.md +1 -1
  9. package/docs/Hooks.md +28 -1
  10. package/docs/Lifecycle.md +8 -1
  11. package/docs/Middleware.md +5 -4
  12. package/docs/Reply.md +13 -4
  13. package/docs/Routes.md +4 -3
  14. package/docs/Server.md +78 -4
  15. package/docs/Serverless.md +23 -51
  16. package/docs/TypeScript.md +35 -18
  17. package/docs/Validation-and-Serialization.md +4 -4
  18. package/docs/Write-Plugin.md +4 -4
  19. package/examples/hooks-benchmark.js +12 -12
  20. package/examples/hooks.js +16 -16
  21. package/examples/plugin.js +2 -2
  22. package/examples/route-prefix.js +4 -4
  23. package/fastify.d.ts +16 -1
  24. package/fastify.js +33 -16
  25. package/isolate-0x426d1e0-1227-v8.log +4019 -0
  26. package/isolate-0x4d4c7e0-1988-v8.log +4081 -0
  27. package/lib/errors.js +6 -0
  28. package/lib/headRoute.js +31 -0
  29. package/lib/pluginOverride.js +5 -5
  30. package/lib/pluginUtils.js +7 -6
  31. package/lib/reply.js +14 -2
  32. package/lib/reqIdGenFactory.js +5 -0
  33. package/lib/request.js +1 -1
  34. package/lib/route.js +66 -41
  35. package/lib/schema-compilers.js +5 -3
  36. package/lib/schema-controller.js +106 -0
  37. package/lib/schemas.js +14 -24
  38. package/lib/server.js +1 -0
  39. package/lib/symbols.js +1 -3
  40. package/lib/warnings.js +2 -0
  41. package/lib/wrapThenable.js +2 -1
  42. package/package.json +25 -21
  43. package/test/404s.test.js +120 -120
  44. package/test/500s.test.js +8 -8
  45. package/test/async-await.test.js +29 -1
  46. package/test/close.test.js +8 -8
  47. package/test/context-config.test.js +52 -0
  48. package/test/custom-parser.test.js +8 -8
  49. package/test/decorator.test.js +49 -49
  50. package/test/default-route.test.js +43 -0
  51. package/test/fastify-instance.test.js +2 -2
  52. package/test/fluent-schema.test.js +3 -3
  53. package/test/handler-context.test.js +2 -2
  54. package/test/hooks-async.test.js +3 -3
  55. package/test/hooks.on-ready.test.js +12 -12
  56. package/test/hooks.test.js +75 -32
  57. package/test/http2/closing.test.js +23 -1
  58. package/test/inject.test.js +6 -6
  59. package/test/input-validation.js +2 -2
  60. package/test/internals/hookRunner.test.js +50 -50
  61. package/test/internals/reply.test.js +47 -22
  62. package/test/internals/request.test.js +3 -9
  63. package/test/internals/version.test.js +2 -2
  64. package/test/logger.test.js +30 -30
  65. package/test/middleware.test.js +4 -4
  66. package/test/plugin.helper.js +2 -2
  67. package/test/plugin.test.js +154 -99
  68. package/test/register.test.js +11 -11
  69. package/test/request-error.test.js +2 -2
  70. package/test/route-hooks.test.js +24 -24
  71. package/test/route-prefix.test.js +81 -52
  72. package/test/route.test.js +568 -0
  73. package/test/schema-feature.test.js +168 -38
  74. package/test/schema-serialization.test.js +4 -4
  75. package/test/schema-special-usage.test.js +136 -0
  76. package/test/schema-validation.test.js +7 -7
  77. package/test/skip-reply-send.test.js +315 -0
  78. package/test/stream.test.js +6 -6
  79. package/test/throw.test.js +4 -4
  80. package/test/types/instance.test-d.ts +5 -3
  81. package/test/types/plugin.test-d.ts +7 -7
  82. package/test/types/reply.test-d.ts +1 -0
  83. package/test/types/schema.test-d.ts +15 -0
  84. package/test/validation-error-handling.test.js +5 -5
  85. package/test/versioned-routes.test.js +1 -1
  86. package/types/content-type-parser.d.ts +1 -1
  87. package/types/instance.d.ts +6 -3
  88. package/types/plugin.d.ts +1 -1
  89. package/types/reply.d.ts +1 -0
  90. package/types/route.d.ts +8 -2
  91. package/types/schema.d.ts +3 -0
  92. package/test/skip-reply-send.js +0 -98
@@ -106,6 +106,31 @@ test('reply.serializer should set a custom serializer', t => {
106
106
  t.equal(reply[kReplySerializer], 'serializer')
107
107
  })
108
108
 
109
+ test('reply.serializer should support running preSerialization hooks', t => {
110
+ t.plan(3)
111
+ const fastify = require('../..')()
112
+
113
+ fastify.addHook('preSerialization', async (request, reply, payload) => { t.ok('called', 'preSerialization') })
114
+ fastify.route({
115
+ method: 'GET',
116
+ url: '/',
117
+ handler: (req, reply) => {
118
+ reply
119
+ .type('application/json')
120
+ .serializer(JSON.stringify)
121
+ .send({ foo: 'bar' })
122
+ }
123
+ })
124
+
125
+ fastify.inject({
126
+ method: 'GET',
127
+ url: '/'
128
+ }, (err, res) => {
129
+ t.error(err)
130
+ t.strictEqual(res.payload, '{"foo":"bar"}')
131
+ })
132
+ })
133
+
109
134
  test('reply.serialize should serialize payload', t => {
110
135
  t.plan(1)
111
136
  const response = { statusCode: 200 }
@@ -212,15 +237,15 @@ test('within an instance', t => {
212
237
  reply.send({ hello: 'world!' })
213
238
  })
214
239
 
215
- fastify.register(function (instance, options, next) {
216
- fastify.addHook('onSend', function (req, reply, payload, next) {
240
+ fastify.register(function (instance, options, done) {
241
+ fastify.addHook('onSend', function (req, reply, payload, done) {
217
242
  reply.header('x-onsend', 'yes')
218
- next()
243
+ done()
219
244
  })
220
245
  fastify.get('/redirect-onsend', function (req, reply) {
221
246
  reply.redirect('/')
222
247
  })
223
- next()
248
+ done()
224
249
  })
225
250
 
226
251
  fastify.listen(0, err => {
@@ -756,9 +781,9 @@ test('undefined payload should be sent as-is', t => {
756
781
 
757
782
  const fastify = require('../..')()
758
783
 
759
- fastify.addHook('onSend', function (request, reply, payload, next) {
784
+ fastify.addHook('onSend', function (request, reply, payload, done) {
760
785
  t.strictEqual(payload, undefined)
761
- next()
786
+ done()
762
787
  })
763
788
 
764
789
  fastify.get('/', function (req, reply) {
@@ -789,9 +814,9 @@ test('for HEAD method, no body should be sent but content-length should be', t =
789
814
  const bodySize = JSON.stringify({ foo: 'bar' }).length
790
815
 
791
816
  fastify.head('/', {
792
- onSend: function (request, reply, payload, next) {
817
+ onSend: function (request, reply, payload, done) {
793
818
  t.strictEqual(payload, undefined)
794
- next()
819
+ done()
795
820
  }
796
821
  }, function (req, reply) {
797
822
  reply.header('content-length', bodySize)
@@ -800,9 +825,9 @@ test('for HEAD method, no body should be sent but content-length should be', t =
800
825
  })
801
826
 
802
827
  fastify.head('/with/null', {
803
- onSend: function (request, reply, payload, next) {
828
+ onSend: function (request, reply, payload, done) {
804
829
  t.strictEqual(payload, 'null')
805
- next()
830
+ done()
806
831
  }
807
832
  }, function (req, reply) {
808
833
  reply.header('content-length', bodySize)
@@ -849,12 +874,12 @@ test('reply.send(new NotFound()) should not invoke the 404 handler', t => {
849
874
  reply.send(new NotFound())
850
875
  })
851
876
 
852
- fastify.register(function (instance, options, next) {
877
+ fastify.register(function (instance, options, done) {
853
878
  instance.get('/not-found', function (req, reply) {
854
879
  reply.send(new NotFound())
855
880
  })
856
881
 
857
- next()
882
+ done()
858
883
  }, { prefix: '/prefixed' })
859
884
 
860
885
  fastify.listen(0, err => {
@@ -1166,9 +1191,9 @@ test('Content type and charset set previously', t => {
1166
1191
 
1167
1192
  const fastify = require('../../')()
1168
1193
 
1169
- fastify.addHook('onRequest', function (req, reply, next) {
1194
+ fastify.addHook('onRequest', function (req, reply, done) {
1170
1195
  reply.header('content-type', 'application/json; charset=utf-16')
1171
- next()
1196
+ done()
1172
1197
  })
1173
1198
 
1174
1199
  fastify.get('/', function (req, reply) {
@@ -1357,7 +1382,7 @@ test('reply should use the right serializer in encapsulated context', t => {
1357
1382
  handler: (req, reply) => { reply.send({ foo: 'bar' }) }
1358
1383
  })
1359
1384
 
1360
- fastify.register(function (instance, opts, next) {
1385
+ fastify.register(function (instance, opts, done) {
1361
1386
  instance.route({
1362
1387
  method: 'GET',
1363
1388
  url: '/sub',
@@ -1368,10 +1393,10 @@ test('reply should use the right serializer in encapsulated context', t => {
1368
1393
  payload.john = 'too too'
1369
1394
  return JSON.stringify(payload)
1370
1395
  })
1371
- next()
1396
+ done()
1372
1397
  })
1373
1398
 
1374
- fastify.register(function (instance, opts, next) {
1399
+ fastify.register(function (instance, opts, done) {
1375
1400
  instance.route({
1376
1401
  method: 'GET',
1377
1402
  url: '/sub',
@@ -1382,7 +1407,7 @@ test('reply should use the right serializer in encapsulated context', t => {
1382
1407
  payload.sweet = 'potato potato'
1383
1408
  return JSON.stringify(payload)
1384
1409
  })
1385
- next()
1410
+ done()
1386
1411
  }, { prefix: 'sub' })
1387
1412
 
1388
1413
  fastify.inject({
@@ -1421,7 +1446,7 @@ test('reply should use the right serializer in deep encapsulated context', t =>
1421
1446
  handler: (req, reply) => { reply.send({ foo: 'bar' }) }
1422
1447
  })
1423
1448
 
1424
- fastify.register(function (instance, opts, next) {
1449
+ fastify.register(function (instance, opts, done) {
1425
1450
  instance.route({
1426
1451
  method: 'GET',
1427
1452
  url: '/sub',
@@ -1433,7 +1458,7 @@ test('reply should use the right serializer in deep encapsulated context', t =>
1433
1458
  return JSON.stringify(payload)
1434
1459
  })
1435
1460
 
1436
- instance.register(function (subInstance, opts, next) {
1461
+ instance.register(function (subInstance, opts, done) {
1437
1462
  subInstance.route({
1438
1463
  method: 'GET',
1439
1464
  url: '/deep',
@@ -1444,9 +1469,9 @@ test('reply should use the right serializer in deep encapsulated context', t =>
1444
1469
  payload.john = 'deep deep'
1445
1470
  return JSON.stringify(payload)
1446
1471
  })
1447
- next()
1472
+ done()
1448
1473
  })
1449
- next()
1474
+ done()
1450
1475
  })
1451
1476
 
1452
1477
  fastify.inject({
@@ -75,10 +75,7 @@ test('Request with trust proxy', t => {
75
75
  const req = {
76
76
  method: 'GET',
77
77
  url: '/',
78
- // Some dependencies (proxy-addr, forwarded) still depend on the deprecated
79
- // .connection property, we use .socket. Include both to satisfy everyone.
80
78
  socket: { remoteAddress: 'ip' },
81
- connection: { remoteAddress: 'ip' },
82
79
  headers
83
80
  }
84
81
 
@@ -109,7 +106,7 @@ test('Request with trust proxy - no x-forwarded-host header', t => {
109
106
  const req = {
110
107
  method: 'GET',
111
108
  url: '/',
112
- connection: { remoteAddress: 'ip' },
109
+ socket: { remoteAddress: 'ip' },
113
110
  headers
114
111
  }
115
112
 
@@ -128,7 +125,7 @@ test('Request with trust proxy - no x-forwarded-host header and fallback to auth
128
125
  const req = {
129
126
  method: 'GET',
130
127
  url: '/',
131
- connection: { remoteAddress: 'ip' },
128
+ socket: { remoteAddress: 'ip' },
132
129
  headers
133
130
  }
134
131
 
@@ -148,7 +145,7 @@ test('Request with trust proxy - x-forwarded-host header has precedence over hos
148
145
  const req = {
149
146
  method: 'GET',
150
147
  url: '/',
151
- connection: { remoteAddress: 'ip' },
148
+ socket: { remoteAddress: 'ip' },
152
149
  headers
153
150
  }
154
151
 
@@ -167,10 +164,7 @@ test('Request with trust proxy - handles multiple entries in x-forwarded-host/pr
167
164
  const req = {
168
165
  method: 'GET',
169
166
  url: '/',
170
- // Some dependencies (proxy-addr, forwarded) still depend on the deprecated
171
- // .connection property, we use .socket. Include both to satisfy everyone.
172
167
  socket: { remoteAddress: 'ip' },
173
- connection: { remoteAddress: 'ip' },
174
168
  headers
175
169
  }
176
170
 
@@ -37,7 +37,7 @@ test('should skip the version check if the version is undefined', t => {
37
37
  t.pass('everything right')
38
38
  })
39
39
 
40
- function plugin (instance, opts, next) {
41
- next()
40
+ function plugin (instance, opts, done) {
41
+ done()
42
42
  }
43
43
  })
@@ -450,12 +450,12 @@ test('The logger should accept custom serializer', t => {
450
450
  stream.once('data', line => {
451
451
  t.ok(line.req, 'req is defined')
452
452
  t.equal(line.msg, 'incoming request', 'message is set')
453
- t.deepEqual(line.req, { url: '/custom' }, 'custom req serialiser is use')
453
+ t.deepEqual(line.req, { url: '/custom' }, 'custom req serializer is use')
454
454
 
455
455
  stream.once('data', line => {
456
456
  t.ok(line.res, 'res is defined')
457
457
  t.equal(line.msg, 'kaboom', 'message is set')
458
- t.deepEqual(line.res, { statusCode: 500 }, 'default res serialiser is use')
458
+ t.deepEqual(line.res, { statusCode: 500 }, 'default res serializer is use')
459
459
  })
460
460
  })
461
461
  })
@@ -540,12 +540,12 @@ test('Should set a custom logLevel for a plugin', t => {
540
540
  reply.send({ hello: 'world' })
541
541
  })
542
542
 
543
- fastify.register(function (instance, opts, next) {
543
+ fastify.register(function (instance, opts, done) {
544
544
  instance.get('/plugin', (req, reply) => {
545
545
  req.log.info('Hello') // we should see this log
546
546
  reply.send({ hello: 'world' })
547
547
  })
548
- next()
548
+ done()
549
549
  }, { logLevel: 'info' })
550
550
 
551
551
  fastify.inject({
@@ -583,12 +583,12 @@ test('Should set a custom logSerializers for a plugin', t => {
583
583
  logger
584
584
  })
585
585
 
586
- fastify.register(function (instance, opts, next) {
586
+ fastify.register(function (instance, opts, done) {
587
587
  instance.get('/plugin', (req, reply) => {
588
588
  req.log.info({ test: 'Hello' }) // we should see this log
589
589
  reply.send({ hello: 'world' })
590
590
  })
591
- next()
591
+ done()
592
592
  }, { logLevel: 'info', logSerializers: { test: value => 'X' + value } })
593
593
 
594
594
  fastify.inject({
@@ -622,22 +622,22 @@ test('Should set a custom logLevel for every plugin', t => {
622
622
  reply.send({ hello: 'world' })
623
623
  })
624
624
 
625
- fastify.register(function (instance, opts, next) {
625
+ fastify.register(function (instance, opts, done) {
626
626
  instance.get('/info', (req, reply) => {
627
627
  req.log.info('info') // we should see this log
628
628
  req.log.debug('hidden log')
629
629
  reply.send({ hello: 'world' })
630
630
  })
631
- next()
631
+ done()
632
632
  }, { logLevel: 'info' })
633
633
 
634
- fastify.register(function (instance, opts, next) {
634
+ fastify.register(function (instance, opts, done) {
635
635
  instance.get('/debug', (req, reply) => {
636
636
  req.log.debug('debug') // we should see this log
637
637
  req.log.trace('hidden log')
638
638
  reply.send({ hello: 'world' })
639
639
  })
640
- next()
640
+ done()
641
641
  }, { logLevel: 'debug' })
642
642
 
643
643
  fastify.inject({
@@ -689,20 +689,20 @@ test('Should set a custom logSerializers for every plugin', async t => {
689
689
  reply.send({ hello: 'world' })
690
690
  })
691
691
 
692
- fastify.register(function (instance, opts, next) {
692
+ fastify.register(function (instance, opts, done) {
693
693
  instance.get('/test1', (req, reply) => {
694
694
  req.log.info({ test: 'Hello' })
695
695
  reply.send({ hello: 'world' })
696
696
  })
697
- next()
697
+ done()
698
698
  }, { logSerializers: { test: value => 'X' + value } })
699
699
 
700
- fastify.register(function (instance, opts, next) {
700
+ fastify.register(function (instance, opts, done) {
701
701
  instance.get('/test2', (req, reply) => {
702
702
  req.log.info({ test: 'Hello' })
703
703
  reply.send({ hello: 'world' })
704
704
  })
705
- next()
705
+ done()
706
706
  }, { logSerializers: { test: value => 'Z' + value } })
707
707
 
708
708
  let res = await fastify.inject({
@@ -739,7 +739,7 @@ test('Should override serializers from route', t => {
739
739
  logger
740
740
  })
741
741
 
742
- fastify.register(function (instance, opts, next) {
742
+ fastify.register(function (instance, opts, done) {
743
743
  instance.get('/', {
744
744
  logSerializers: {
745
745
  test: value => 'Z' + value // should override
@@ -748,7 +748,7 @@ test('Should override serializers from route', t => {
748
748
  req.log.info({ test: 'Hello' })
749
749
  reply.send({ hello: 'world' })
750
750
  })
751
- next()
751
+ done()
752
752
  }, { logSerializers: { test: value => 'X' + value } })
753
753
 
754
754
  fastify.inject({
@@ -776,21 +776,21 @@ test('Should override serializers from plugin', t => {
776
776
  logger
777
777
  })
778
778
 
779
- fastify.register(function (instance, opts, next) {
779
+ fastify.register(function (instance, opts, done) {
780
780
  instance.register(context1, {
781
781
  logSerializers: {
782
782
  test: value => 'Z' + value // should override
783
783
  }
784
784
  })
785
- next()
785
+ done()
786
786
  }, { logSerializers: { test: value => 'X' + value } })
787
787
 
788
- function context1 (instance, opts, next) {
788
+ function context1 (instance, opts, done) {
789
789
  instance.get('/', (req, reply) => {
790
790
  req.log.info({ test: 'Hello' })
791
791
  reply.send({ hello: 'world' })
792
792
  })
793
- next()
793
+ done()
794
794
  }
795
795
 
796
796
  fastify.inject({
@@ -825,7 +825,7 @@ test('Should use serializers from plugin and route', t => {
825
825
  logSerializers: { test: value => 'X' + value }
826
826
  })
827
827
 
828
- function context1 (instance, opts, next) {
828
+ function context1 (instance, opts, done) {
829
829
  instance.get('/', {
830
830
  logSerializers: {
831
831
  test2: value => 'Z' + value
@@ -834,7 +834,7 @@ test('Should use serializers from plugin and route', t => {
834
834
  req.log.info({ test: 'Hello', test2: 'Hello' }) // { test: 'XHello', test2: 'ZHello' }
835
835
  reply.send({ hello: 'world' })
836
836
  })
837
- next()
837
+ done()
838
838
  }
839
839
 
840
840
  fastify.inject({
@@ -912,7 +912,7 @@ test('Should use serializers inherit from contexts', t => {
912
912
  const fastify = Fastify({ logger })
913
913
  fastify.register(context1, { logSerializers: { test2: value => 'Y' + value } })
914
914
 
915
- function context1 (instance, opts, next) {
915
+ function context1 (instance, opts, done) {
916
916
  instance.get('/', {
917
917
  logSerializers: {
918
918
  test3: value => 'Z' + value
@@ -921,7 +921,7 @@ test('Should use serializers inherit from contexts', t => {
921
921
  req.log.info({ test: 'Hello', test2: 'Hello', test3: 'Hello' }) // { test: 'XHello', test2: 'YHello', test3: 'ZHello' }
922
922
  reply.send({ hello: 'world' })
923
923
  })
924
- next()
924
+ done()
925
925
  }
926
926
 
927
927
  fastify.inject({
@@ -949,12 +949,12 @@ test('Should increase the log level for a specific plugin', t => {
949
949
  logger
950
950
  })
951
951
 
952
- fastify.register(function (instance, opts, next) {
952
+ fastify.register(function (instance, opts, done) {
953
953
  instance.get('/', (req, reply) => {
954
954
  req.log.error('Hello') // we should see this log
955
955
  reply.send({ hello: 'world' })
956
956
  })
957
- next()
957
+ done()
958
958
  }, { logLevel: 'error' })
959
959
 
960
960
  fastify.inject({
@@ -982,12 +982,12 @@ test('Should set the log level for the customized 404 handler', t => {
982
982
  logger
983
983
  })
984
984
 
985
- fastify.register(function (instance, opts, next) {
985
+ fastify.register(function (instance, opts, done) {
986
986
  instance.setNotFoundHandler(function (req, reply) {
987
987
  req.log.error('Hello')
988
988
  reply.code(404).send()
989
989
  })
990
- next()
990
+ done()
991
991
  }, { logLevel: 'error' })
992
992
 
993
993
  fastify.inject({
@@ -1014,7 +1014,7 @@ test('Should set the log level for the customized 500 handler', t => {
1014
1014
  logger
1015
1015
  })
1016
1016
 
1017
- fastify.register(function (instance, opts, next) {
1017
+ fastify.register(function (instance, opts, done) {
1018
1018
  instance.get('/', (req, reply) => {
1019
1019
  req.log.error('kaboom')
1020
1020
  reply.send(new Error('kaboom'))
@@ -1024,7 +1024,7 @@ test('Should set the log level for the customized 500 handler', t => {
1024
1024
  reply.log.fatal('Hello')
1025
1025
  reply.code(500).send()
1026
1026
  })
1027
- next()
1027
+ done()
1028
1028
  }, { logLevel: 'fatal' })
1029
1029
 
1030
1030
  fastify.inject({
@@ -41,20 +41,20 @@ test('Encapsulation works', t => {
41
41
  t.plan(2)
42
42
  const fastify = Fastify()
43
43
 
44
- fastify.register((instance, opts, next) => {
44
+ fastify.register((instance, opts, done) => {
45
45
  instance.decorate('use', () => true)
46
46
  t.strictEqual(instance.use(), true)
47
- next()
47
+ done()
48
48
  })
49
49
 
50
- fastify.register((instance, opts, next) => {
50
+ fastify.register((instance, opts, done) => {
51
51
  try {
52
52
  instance.use()
53
53
  t.fail('Should throw')
54
54
  } catch (err) {
55
55
  t.ok(err instanceof FST_ERR_MISSING_MIDDLEWARE)
56
56
  }
57
- next()
57
+ done()
58
58
  })
59
59
 
60
60
  fastify.ready()
@@ -2,7 +2,7 @@
2
2
 
3
3
  const fp = require('fastify-plugin')
4
4
 
5
- module.exports = fp(function (fastify, opts, next) {
5
+ module.exports = fp(function (fastify, opts, done) {
6
6
  fastify.decorate('test', () => {})
7
- next()
7
+ done()
8
8
  })