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
@@ -6,11 +6,11 @@ const Fastify = require('../')
6
6
 
7
7
  process.removeAllListeners('warning')
8
8
 
9
- function endMiddleware (nextOrPayload, next) {
10
- if (typeof nextOrPayload === 'function') {
11
- nextOrPayload()
9
+ function endRouteHook (doneOrPayload, done) {
10
+ if (typeof doneOrPayload === 'function') {
11
+ doneOrPayload()
12
12
  } else {
13
- next()
13
+ done()
14
14
  }
15
15
  }
16
16
 
@@ -20,9 +20,9 @@ function testExecutionHook (hook) {
20
20
  const fastify = Fastify()
21
21
 
22
22
  fastify.post('/', {
23
- [hook]: (req, reply, nextOrPayload, next) => {
23
+ [hook]: (req, reply, doneOrPayload, done) => {
24
24
  t.pass('hook called')
25
- endMiddleware(nextOrPayload, next)
25
+ endRouteHook(doneOrPayload, done)
26
26
  }
27
27
  }, (req, reply) => {
28
28
  reply.send(req.body)
@@ -46,15 +46,15 @@ function testExecutionHook (hook) {
46
46
  get: function () { return ++this.calledTimes }
47
47
  })
48
48
 
49
- fastify.addHook(hook, (req, reply, nextOrPayload, next) => {
49
+ fastify.addHook(hook, (req, reply, doneOrPayload, done) => {
50
50
  t.equal(checker.check, 1)
51
- endMiddleware(nextOrPayload, next)
51
+ endRouteHook(doneOrPayload, done)
52
52
  })
53
53
 
54
54
  fastify.post('/', {
55
- [hook]: (req, reply, nextOrPayload, next) => {
55
+ [hook]: (req, reply, doneOrPayload, done) => {
56
56
  t.equal(checker.check, 2)
57
- endMiddleware(nextOrPayload, next)
57
+ endRouteHook(doneOrPayload, done)
58
58
  }
59
59
  }, (req, reply) => {
60
60
  reply.send({})
@@ -78,13 +78,13 @@ function testExecutionHook (hook) {
78
78
 
79
79
  fastify.post('/', {
80
80
  [hook]: [
81
- (req, reply, nextOrPayload, next) => {
81
+ (req, reply, doneOrPayload, done) => {
82
82
  t.equal(checker.check, 1)
83
- endMiddleware(nextOrPayload, next)
83
+ endRouteHook(doneOrPayload, done)
84
84
  },
85
- (req, reply, nextOrPayload, next) => {
85
+ (req, reply, doneOrPayload, done) => {
86
86
  t.equal(checker.check, 2)
87
- endMiddleware(nextOrPayload, next)
87
+ endRouteHook(doneOrPayload, done)
88
88
  }
89
89
  ]
90
90
  }, (req, reply) => {
@@ -107,15 +107,15 @@ function testExecutionHook (hook) {
107
107
  get: function () { return ++this.calledTimes }
108
108
  })
109
109
 
110
- fastify.addHook(hook, (req, reply, nextOrPayload, next) => {
110
+ fastify.addHook(hook, (req, reply, doneOrPayload, done) => {
111
111
  t.equal(checker.check, 1)
112
- endMiddleware(nextOrPayload, next)
112
+ endRouteHook(doneOrPayload, done)
113
113
  })
114
114
 
115
115
  fastify.post('/', {
116
- [hook]: (req, reply, nextOrPayload, next) => {
116
+ [hook]: (req, reply, doneOrPayload, done) => {
117
117
  t.equal(checker.check, 2)
118
- endMiddleware(nextOrPayload, next)
118
+ endRouteHook(doneOrPayload, done)
119
119
  }
120
120
  }, handler)
121
121
 
@@ -365,9 +365,9 @@ test('preValidation option should be called before preHandler hook', t => {
365
365
  t.plan(3)
366
366
  const fastify = Fastify()
367
367
 
368
- fastify.addHook('preHandler', (req, reply, next) => {
368
+ fastify.addHook('preHandler', (req, reply, done) => {
369
369
  t.true(req.called)
370
- next()
370
+ done()
371
371
  })
372
372
 
373
373
  fastify.post('/', {
@@ -416,9 +416,9 @@ test('preParsing option should be called before preValidation hook', t => {
416
416
  t.plan(3)
417
417
  const fastify = Fastify()
418
418
 
419
- fastify.addHook('preValidation', (req, reply, next) => {
419
+ fastify.addHook('preValidation', (req, reply, done) => {
420
420
  t.true(req.called)
421
- next()
421
+ done()
422
422
  })
423
423
 
424
424
  fastify.post('/', {
@@ -472,9 +472,9 @@ test('onRequest option should be called before preParsing', t => {
472
472
  t.plan(3)
473
473
  const fastify = Fastify()
474
474
 
475
- fastify.addHook('preParsing', (req, reply, next) => {
475
+ fastify.addHook('preParsing', (req, reply, done) => {
476
476
  t.true(req.called)
477
- next()
477
+ done()
478
478
  })
479
479
 
480
480
  fastify.post('/', {
@@ -12,19 +12,19 @@ test('Prefix options should add a prefix for all the routes inside a register /
12
12
  reply.send({ route: '/first' })
13
13
  })
14
14
 
15
- fastify.register(function (fastify, opts, next) {
15
+ fastify.register(function (fastify, opts, done) {
16
16
  fastify.get('/first', (req, reply) => {
17
17
  reply.send({ route: '/v1/first' })
18
18
  })
19
19
 
20
- fastify.register(function (fastify, opts, next) {
20
+ fastify.register(function (fastify, opts, done) {
21
21
  fastify.get('/first', (req, reply) => {
22
22
  reply.send({ route: '/v1/v2/first' })
23
23
  })
24
- next()
24
+ done()
25
25
  }, { prefix: '/v2' })
26
26
 
27
- next()
27
+ done()
28
28
  }, { prefix: '/v1' })
29
29
 
30
30
  fastify.inject({
@@ -56,7 +56,7 @@ test('Prefix options should add a prefix for all the routes inside a register /
56
56
  t.plan(4)
57
57
  const fastify = Fastify()
58
58
 
59
- fastify.register(function (fastify, opts, next) {
59
+ fastify.register(function (fastify, opts, done) {
60
60
  fastify.get('/first', (req, reply) => {
61
61
  reply.send({ route: '/v1/first' })
62
62
  })
@@ -64,7 +64,7 @@ test('Prefix options should add a prefix for all the routes inside a register /
64
64
  fastify.get('/second', (req, reply) => {
65
65
  reply.send({ route: '/v1/second' })
66
66
  })
67
- next()
67
+ done()
68
68
  }, { prefix: '/v1' })
69
69
 
70
70
  fastify.inject({
@@ -89,7 +89,7 @@ test('Prefix options should add a prefix for all the chained routes inside a reg
89
89
 
90
90
  const fastify = Fastify()
91
91
 
92
- fastify.register(function (fastify, opts, next) {
92
+ fastify.register(function (fastify, opts, done) {
93
93
  fastify
94
94
  .get('/first', (req, reply) => {
95
95
  reply.send({ route: '/v1/first' })
@@ -97,7 +97,7 @@ test('Prefix options should add a prefix for all the chained routes inside a reg
97
97
  .get('/second', (req, reply) => {
98
98
  reply.send({ route: '/v1/second' })
99
99
  })
100
- next()
100
+ done()
101
101
  }, { prefix: '/v1' })
102
102
 
103
103
  fastify.inject({
@@ -121,11 +121,11 @@ test('Prefix should support parameters as well', t => {
121
121
  t.plan(2)
122
122
  const fastify = Fastify()
123
123
 
124
- fastify.register(function (fastify, opts, next) {
124
+ fastify.register(function (fastify, opts, done) {
125
125
  fastify.get('/hello', (req, reply) => {
126
126
  reply.send({ id: req.params.id })
127
127
  })
128
- next()
128
+ done()
129
129
  }, { prefix: '/v1/:id' })
130
130
 
131
131
  fastify.inject({
@@ -141,11 +141,11 @@ test('Prefix should support /', t => {
141
141
  t.plan(2)
142
142
  const fastify = Fastify()
143
143
 
144
- fastify.register(function (fastify, opts, next) {
144
+ fastify.register(function (fastify, opts, done) {
145
145
  fastify.get('/', (req, reply) => {
146
146
  reply.send({ hello: 'world' })
147
147
  })
148
- next()
148
+ done()
149
149
  }, { prefix: '/v1' })
150
150
 
151
151
  fastify.inject({
@@ -161,11 +161,11 @@ test('Prefix without /', t => {
161
161
  t.plan(2)
162
162
  const fastify = Fastify()
163
163
 
164
- fastify.register(function (fastify, opts, next) {
164
+ fastify.register(function (fastify, opts, done) {
165
165
  fastify.get('/', (req, reply) => {
166
166
  reply.send({ hello: 'world' })
167
167
  })
168
- next()
168
+ done()
169
169
  }, { prefix: 'v1' })
170
170
 
171
171
  fastify.inject({
@@ -181,7 +181,7 @@ test('Prefix with trailing /', t => {
181
181
  t.plan(6)
182
182
  const fastify = Fastify()
183
183
 
184
- fastify.register(function (fastify, opts, next) {
184
+ fastify.register(function (fastify, opts, done) {
185
185
  fastify.get('/route1', (req, reply) => {
186
186
  reply.send({ hello: 'world1' })
187
187
  })
@@ -189,14 +189,14 @@ test('Prefix with trailing /', t => {
189
189
  reply.send({ hello: 'world2' })
190
190
  })
191
191
 
192
- fastify.register(function (fastify, opts, next) {
192
+ fastify.register(function (fastify, opts, done) {
193
193
  fastify.get('/route3', (req, reply) => {
194
194
  reply.send({ hello: 'world3' })
195
195
  })
196
- next()
196
+ done()
197
197
  }, { prefix: '/inner/' })
198
198
 
199
- next()
199
+ done()
200
200
  }, { prefix: '/v1/' })
201
201
 
202
202
  fastify.inject({
@@ -228,20 +228,20 @@ test('Prefix works multiple levels deep', t => {
228
228
  t.plan(2)
229
229
  const fastify = Fastify()
230
230
 
231
- fastify.register(function (fastify, opts, next) {
232
- fastify.register(function (fastify, opts, next) {
233
- fastify.register(function (fastify, opts, next) {
234
- fastify.register(function (fastify, opts, next) {
231
+ fastify.register(function (fastify, opts, done) {
232
+ fastify.register(function (fastify, opts, done) {
233
+ fastify.register(function (fastify, opts, done) {
234
+ fastify.register(function (fastify, opts, done) {
235
235
  fastify.get('/', (req, reply) => {
236
236
  reply.send({ hello: 'world' })
237
237
  })
238
- next()
238
+ done()
239
239
  }, { prefix: '/v3' })
240
- next()
240
+ done()
241
241
  }) // No prefix on this level
242
- next()
242
+ done()
243
243
  }, { prefix: 'v2' })
244
- next()
244
+ done()
245
245
  }, { prefix: '/v1' })
246
246
 
247
247
  fastify.inject({
@@ -261,24 +261,24 @@ test('Different register - encapsulation check', t => {
261
261
  reply.send({ route: '/first' })
262
262
  })
263
263
 
264
- fastify.register(function (instance, opts, next) {
265
- instance.register(function (f, opts, next) {
264
+ fastify.register(function (instance, opts, done) {
265
+ instance.register(function (f, opts, done) {
266
266
  f.get('/', (req, reply) => {
267
267
  reply.send({ route: '/v1/v2' })
268
268
  })
269
- next()
269
+ done()
270
270
  }, { prefix: '/v2' })
271
- next()
271
+ done()
272
272
  }, { prefix: '/v1' })
273
273
 
274
- fastify.register(function (instance, opts, next) {
275
- instance.register(function (f, opts, next) {
274
+ fastify.register(function (instance, opts, done) {
275
+ instance.register(function (f, opts, done) {
276
276
  f.get('/', (req, reply) => {
277
277
  reply.send({ route: '/v3/v4' })
278
278
  })
279
- next()
279
+ done()
280
280
  }, { prefix: '/v4' })
281
- next()
281
+ done()
282
282
  }, { prefix: '/v3' })
283
283
 
284
284
  fastify.inject({
@@ -302,19 +302,19 @@ test('Can retrieve prefix within encapsulated instances', t => {
302
302
  t.plan(4)
303
303
  const fastify = Fastify()
304
304
 
305
- fastify.register(function (instance, opts, next) {
305
+ fastify.register(function (instance, opts, done) {
306
306
  instance.get('/one', function (req, reply) {
307
307
  reply.send(instance.prefix)
308
308
  })
309
309
 
310
- instance.register(function (instance, opts, next) {
310
+ instance.register(function (instance, opts, done) {
311
311
  instance.get('/two', function (req, reply) {
312
312
  reply.send(instance.prefix)
313
313
  })
314
- next()
314
+ done()
315
315
  }, { prefix: '/v2' })
316
316
 
317
- next()
317
+ done()
318
318
  }, { prefix: '/v1' })
319
319
 
320
320
  fastify.inject({
@@ -338,12 +338,12 @@ test('matches both /prefix and /prefix/ with a / route', t => {
338
338
  t.plan(4)
339
339
  const fastify = Fastify()
340
340
 
341
- fastify.register(function (fastify, opts, next) {
341
+ fastify.register(function (fastify, opts, done) {
342
342
  fastify.get('/', (req, reply) => {
343
343
  reply.send({ hello: 'world' })
344
344
  })
345
345
 
346
- next()
346
+ done()
347
347
  }, { prefix: '/prefix' })
348
348
 
349
349
  fastify.inject({
@@ -367,12 +367,12 @@ test('prefix "/prefix/" does not match "/prefix" with a / route', t => {
367
367
  t.plan(4)
368
368
  const fastify = Fastify()
369
369
 
370
- fastify.register(function (fastify, opts, next) {
370
+ fastify.register(function (fastify, opts, done) {
371
371
  fastify.get('/', (req, reply) => {
372
372
  reply.send({ hello: 'world' })
373
373
  })
374
374
 
375
- next()
375
+ done()
376
376
  }, { prefix: '/prefix/' })
377
377
 
378
378
  fastify.inject({
@@ -398,12 +398,12 @@ test('matches both /prefix and /prefix/ with a / route - ignoreTrailingSlash: tr
398
398
  ignoreTrailingSlash: true
399
399
  })
400
400
 
401
- fastify.register(function (fastify, opts, next) {
401
+ fastify.register(function (fastify, opts, done) {
402
402
  fastify.get('/', (req, reply) => {
403
403
  reply.send({ hello: 'world' })
404
404
  })
405
405
 
406
- next()
406
+ done()
407
407
  }, { prefix: '/prefix' })
408
408
 
409
409
  fastify.inject({
@@ -429,7 +429,7 @@ test('matches both /prefix and /prefix/ with a / route - prefixTrailingSlash: "
429
429
  ignoreTrailingSlash: false
430
430
  })
431
431
 
432
- fastify.register(function (fastify, opts, next) {
432
+ fastify.register(function (fastify, opts, done) {
433
433
  fastify.route({
434
434
  method: 'GET',
435
435
  url: '/',
@@ -439,7 +439,7 @@ test('matches both /prefix and /prefix/ with a / route - prefixTrailingSlash: "
439
439
  }
440
440
  })
441
441
 
442
- next()
442
+ done()
443
443
  }, { prefix: '/prefix' })
444
444
 
445
445
  fastify.inject({
@@ -465,7 +465,7 @@ test('returns 404 status code with /prefix/ and / route - prefixTrailingSlash: "
465
465
  ignoreTrailingSlash: true
466
466
  })
467
467
 
468
- fastify.register(function (fastify, opts, next) {
468
+ fastify.register(function (fastify, opts, done) {
469
469
  fastify.route({
470
470
  method: 'GET',
471
471
  url: '/',
@@ -474,7 +474,7 @@ test('returns 404 status code with /prefix/ and / route - prefixTrailingSlash: "
474
474
  }
475
475
  })
476
476
 
477
- next()
477
+ done()
478
478
  }, { prefix: '/prefix/' })
479
479
 
480
480
  fastify.inject({
@@ -496,7 +496,7 @@ test('matches only /prefix with a / route - prefixTrailingSlash: "no-slash", ig
496
496
  ignoreTrailingSlash: false
497
497
  })
498
498
 
499
- fastify.register(function (fastify, opts, next) {
499
+ fastify.register(function (fastify, opts, done) {
500
500
  fastify.route({
501
501
  method: 'GET',
502
502
  url: '/',
@@ -506,7 +506,7 @@ test('matches only /prefix with a / route - prefixTrailingSlash: "no-slash", ig
506
506
  }
507
507
  })
508
508
 
509
- next()
509
+ done()
510
510
  }, { prefix: '/prefix' })
511
511
 
512
512
  fastify.inject({
@@ -532,7 +532,7 @@ test('matches only /prefix/ with a / route - prefixTrailingSlash: "slash", igno
532
532
  ignoreTrailingSlash: false
533
533
  })
534
534
 
535
- fastify.register(function (fastify, opts, next) {
535
+ fastify.register(function (fastify, opts, done) {
536
536
  fastify.route({
537
537
  method: 'GET',
538
538
  url: '/',
@@ -542,7 +542,7 @@ test('matches only /prefix/ with a / route - prefixTrailingSlash: "slash", igno
542
542
  }
543
543
  })
544
544
 
545
- next()
545
+ done()
546
546
  }, { prefix: '/prefix' })
547
547
 
548
548
  fastify.inject({
@@ -561,3 +561,32 @@ test('matches only /prefix/ with a / route - prefixTrailingSlash: "slash", igno
561
561
  t.equal(JSON.parse(res.payload).statusCode, 404)
562
562
  })
563
563
  })
564
+
565
+ test('calls onRoute only once when prefixing', async t => {
566
+ t.plan(1)
567
+ const fastify = Fastify({
568
+ ignoreTrailingSlash: false
569
+ })
570
+
571
+ let onRouteCalled = 0
572
+ fastify.register(function (fastify, opts, next) {
573
+ fastify.addHook('onRoute', () => {
574
+ onRouteCalled++
575
+ })
576
+
577
+ fastify.route({
578
+ method: 'GET',
579
+ url: '/',
580
+ prefixTrailingSlash: 'both',
581
+ handler: (req, reply) => {
582
+ reply.send({ hello: 'world' })
583
+ }
584
+ })
585
+
586
+ next()
587
+ }, { prefix: '/prefix' })
588
+
589
+ await fastify.ready()
590
+
591
+ t.deepEqual(onRouteCalled, 1)
592
+ })