fastify 5.3.3 → 5.5.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 (137) hide show
  1. package/.vscode/settings.json +15 -15
  2. package/LICENSE +1 -1
  3. package/README.md +2 -0
  4. package/SECURITY.md +158 -2
  5. package/build/build-validation.js +20 -1
  6. package/docs/Guides/Delay-Accepting-Requests.md +8 -5
  7. package/docs/Guides/Ecosystem.md +20 -5
  8. package/docs/Guides/Migration-Guide-V5.md +6 -10
  9. package/docs/Guides/Recommendations.md +1 -1
  10. package/docs/Reference/ContentTypeParser.md +1 -1
  11. package/docs/Reference/Errors.md +5 -3
  12. package/docs/Reference/Hooks.md +16 -20
  13. package/docs/Reference/Lifecycle.md +2 -2
  14. package/docs/Reference/Logging.md +3 -3
  15. package/docs/Reference/Middleware.md +1 -1
  16. package/docs/Reference/Reply.md +8 -8
  17. package/docs/Reference/Request.md +2 -2
  18. package/docs/Reference/Routes.md +7 -6
  19. package/docs/Reference/Server.md +341 -200
  20. package/docs/Reference/TypeScript.md +1 -3
  21. package/docs/Reference/Validation-and-Serialization.md +56 -4
  22. package/docs/Reference/Warnings.md +2 -1
  23. package/fastify.d.ts +4 -3
  24. package/fastify.js +47 -34
  25. package/lib/configValidator.js +196 -28
  26. package/lib/contentTypeParser.js +41 -48
  27. package/lib/error-handler.js +3 -3
  28. package/lib/errors.js +11 -0
  29. package/lib/handleRequest.js +13 -17
  30. package/lib/pluginOverride.js +3 -1
  31. package/lib/promise.js +23 -0
  32. package/lib/reply.js +24 -30
  33. package/lib/request.js +3 -10
  34. package/lib/route.js +37 -3
  35. package/lib/server.js +36 -35
  36. package/lib/symbols.js +1 -0
  37. package/lib/warnings.js +19 -1
  38. package/package.json +14 -10
  39. package/test/404s.test.js +226 -325
  40. package/test/allow-unsafe-regex.test.js +19 -48
  41. package/test/als.test.js +28 -40
  42. package/test/async-await.test.js +84 -128
  43. package/test/async_hooks.test.js +18 -37
  44. package/test/body-limit.test.js +90 -63
  45. package/test/buffer.test.js +22 -0
  46. package/test/build-certificate.js +1 -1
  47. package/test/case-insensitive.test.js +44 -65
  48. package/test/check.test.js +17 -21
  49. package/test/close-pipelining.test.js +24 -15
  50. package/test/constrained-routes.test.js +231 -0
  51. package/test/custom-http-server.test.js +7 -15
  52. package/test/custom-parser-async.test.js +17 -22
  53. package/test/custom-parser.0.test.js +267 -348
  54. package/test/custom-parser.1.test.js +141 -191
  55. package/test/custom-parser.2.test.js +34 -44
  56. package/test/custom-parser.3.test.js +56 -104
  57. package/test/custom-parser.4.test.js +106 -144
  58. package/test/custom-parser.5.test.js +56 -75
  59. package/test/custom-querystring-parser.test.js +51 -77
  60. package/test/decorator-namespace.test._js_ +3 -4
  61. package/test/decorator.test.js +76 -259
  62. package/test/delete.test.js +101 -110
  63. package/test/diagnostics-channel/404.test.js +7 -15
  64. package/test/diagnostics-channel/async-delay-request.test.js +7 -16
  65. package/test/diagnostics-channel/async-request.test.js +8 -16
  66. package/test/diagnostics-channel/error-request.test.js +7 -15
  67. package/test/diagnostics-channel/sync-delay-request.test.js +7 -16
  68. package/test/diagnostics-channel/sync-request-reply.test.js +9 -16
  69. package/test/diagnostics-channel/sync-request.test.js +9 -16
  70. package/test/fastify-instance.test.js +1 -1
  71. package/test/header-overflow.test.js +18 -29
  72. package/test/helper.js +139 -135
  73. package/test/hooks-async.test.js +259 -235
  74. package/test/hooks.test.js +951 -996
  75. package/test/http-methods/copy.test.js +14 -19
  76. package/test/http-methods/get.test.js +131 -143
  77. package/test/http-methods/head.test.js +53 -84
  78. package/test/http-methods/lock.test.js +31 -31
  79. package/test/http-methods/mkcalendar.test.js +45 -72
  80. package/test/http-methods/mkcol.test.js +5 -9
  81. package/test/http-methods/move.test.js +6 -10
  82. package/test/http-methods/propfind.test.js +34 -44
  83. package/test/http-methods/proppatch.test.js +23 -29
  84. package/test/http-methods/report.test.js +44 -69
  85. package/test/http-methods/search.test.js +67 -82
  86. package/test/http-methods/unlock.test.js +5 -9
  87. package/test/http2/closing.test.js +38 -20
  88. package/test/http2/secure-with-fallback.test.js +31 -28
  89. package/test/https/custom-https-server.test.js +9 -13
  90. package/test/https/https.test.js +56 -53
  91. package/test/input-validation.js +139 -150
  92. package/test/internals/errors.test.js +50 -1
  93. package/test/internals/handle-request.test.js +72 -65
  94. package/test/internals/promise.test.js +63 -0
  95. package/test/internals/reply.test.js +277 -496
  96. package/test/issue-4959.test.js +12 -3
  97. package/test/listen.4.test.js +31 -43
  98. package/test/nullable-validation.test.js +33 -46
  99. package/test/output-validation.test.js +24 -26
  100. package/test/plugin.1.test.js +40 -68
  101. package/test/plugin.2.test.js +108 -120
  102. package/test/plugin.3.test.js +50 -72
  103. package/test/plugin.4.test.js +124 -119
  104. package/test/promises.test.js +42 -63
  105. package/test/proto-poisoning.test.js +78 -97
  106. package/test/register.test.js +8 -18
  107. package/test/request-error.test.js +57 -146
  108. package/test/request-id.test.js +30 -49
  109. package/test/route-hooks.test.js +117 -101
  110. package/test/route-prefix.test.js +194 -133
  111. package/test/route-shorthand.test.js +9 -27
  112. package/test/route.1.test.js +74 -131
  113. package/test/route.8.test.js +9 -17
  114. package/test/router-options.test.js +450 -0
  115. package/test/schema-serialization.test.js +177 -154
  116. package/test/schema-special-usage.test.js +165 -132
  117. package/test/schema-validation.test.js +254 -218
  118. package/test/server.test.js +143 -5
  119. package/test/set-error-handler.test.js +58 -1
  120. package/test/skip-reply-send.test.js +64 -69
  121. package/test/stream.1.test.js +33 -50
  122. package/test/stream.4.test.js +18 -28
  123. package/test/stream.5.test.js +11 -19
  124. package/test/trust-proxy.test.js +32 -58
  125. package/test/types/errors.test-d.ts +13 -1
  126. package/test/types/fastify.test-d.ts +3 -0
  127. package/test/types/request.test-d.ts +1 -0
  128. package/test/types/type-provider.test-d.ts +55 -0
  129. package/test/url-rewriting.test.js +45 -62
  130. package/test/use-semicolon-delimiter.test.js +117 -59
  131. package/test/versioned-routes.test.js +39 -56
  132. package/types/errors.d.ts +11 -1
  133. package/types/hooks.d.ts +1 -1
  134. package/types/instance.d.ts +1 -1
  135. package/types/reply.d.ts +2 -2
  136. package/types/request.d.ts +1 -0
  137. package/.taprc +0 -7
@@ -2,10 +2,9 @@
2
2
 
3
3
  const { test } = require('node:test')
4
4
  const Fastify = require('..')
5
- const sget = require('simple-get').concat
6
5
 
7
- test('Should rewrite url', (t, done) => {
8
- t.plan(5)
6
+ test('Should rewrite url', async t => {
7
+ t.plan(4)
9
8
  const fastify = Fastify({
10
9
  rewriteUrl (req) {
11
10
  t.assert.strictEqual(req.url, '/this-would-404-without-url-rewrite')
@@ -22,24 +21,19 @@ test('Should rewrite url', (t, done) => {
22
21
  }
23
22
  })
24
23
 
25
- fastify.listen({ port: 0 }, function (err) {
26
- t.assert.ifError(err)
27
-
28
- t.after(() => fastify.close())
29
- sget({
30
- method: 'GET',
31
- url: 'http://localhost:' + fastify.server.address().port + '/this-would-404-without-url-rewrite'
32
- }, (err, response, body) => {
33
- t.assert.ifError(err)
34
- t.assert.deepStrictEqual(JSON.parse(body), { hello: 'world' })
35
- t.assert.strictEqual(response.statusCode, 200)
36
- done()
37
- })
38
- })
24
+ const fastifyServer = await fastify.listen({ port: 0 })
25
+
26
+ t.after(() => fastify.close())
27
+
28
+ const result = await fetch(`${fastifyServer}/this-would-404-without-url-rewrite`)
29
+
30
+ t.assert.ok(result.ok)
31
+ t.assert.strictEqual(result.status, 200)
32
+ t.assert.deepStrictEqual(await result.json(), { hello: 'world' })
39
33
  })
40
34
 
41
- test('Should not rewrite if the url is the same', (t, done) => {
42
- t.plan(4)
35
+ test('Should not rewrite if the url is the same', async t => {
36
+ t.plan(3)
43
37
  const fastify = Fastify({
44
38
  rewriteUrl (req) {
45
39
  t.assert.strictEqual(req.url, '/this-would-404-without-url-rewrite')
@@ -56,22 +50,18 @@ test('Should not rewrite if the url is the same', (t, done) => {
56
50
  }
57
51
  })
58
52
 
59
- fastify.listen({ port: 0 }, function (err) {
60
- t.assert.ifError(err)
61
- t.after(() => fastify.close())
62
- sget({
63
- method: 'GET',
64
- url: 'http://localhost:' + fastify.server.address().port + '/this-would-404-without-url-rewrite'
65
- }, (err, response, body) => {
66
- t.assert.ifError(err)
67
- t.assert.strictEqual(response.statusCode, 404)
68
- done()
69
- })
70
- })
53
+ const fastifyServer = await fastify.listen({ port: 0 })
54
+
55
+ t.after(() => fastify.close())
56
+
57
+ const result = await fetch(`${fastifyServer}/this-would-404-without-url-rewrite`)
58
+
59
+ t.assert.ok(!result.ok)
60
+ t.assert.strictEqual(result.status, 404)
71
61
  })
72
62
 
73
- test('Should throw an error', (t, done) => {
74
- t.plan(5)
63
+ test('Should throw an error', async t => {
64
+ t.plan(2)
75
65
  const fastify = Fastify({
76
66
  rewriteUrl (req) {
77
67
  t.assert.strictEqual(req.url, '/this-would-404-without-url-rewrite')
@@ -88,23 +78,20 @@ test('Should throw an error', (t, done) => {
88
78
  }
89
79
  })
90
80
 
91
- fastify.listen({ port: 0 }, function (err) {
92
- t.assert.ifError(err)
93
- t.after(() => fastify.close())
94
- sget({
95
- method: 'GET',
96
- url: 'http://localhost:' + fastify.server.address().port + '/this-would-404-without-url-rewrite'
97
- }, (err, response, body) => {
98
- t.assert.strictEqual(err.code, 'ECONNRESET')
99
- t.assert.strictEqual(response, undefined)
100
- t.assert.strictEqual(body, undefined)
101
- done()
102
- })
103
- })
81
+ const fastifyServer = await fastify.listen({ port: 0 })
82
+
83
+ t.after(() => fastify.close())
84
+
85
+ try {
86
+ await fetch(`${fastifyServer}/this-would-404-without-url-rewrite`)
87
+ t.assert.fail('Expected fetch to throw an error')
88
+ } catch (err) {
89
+ t.assert.ok(err instanceof Error)
90
+ }
104
91
  })
105
92
 
106
- test('Should rewrite url but keep originalUrl unchanged', (t, done) => {
107
- t.plan(7)
93
+ test('Should rewrite url but keep originalUrl unchanged', async t => {
94
+ t.plan(6)
108
95
  const fastify = Fastify({
109
96
  rewriteUrl (req) {
110
97
  t.assert.strictEqual(req.url, '/this-would-404-without-url-rewrite')
@@ -122,18 +109,14 @@ test('Should rewrite url but keep originalUrl unchanged', (t, done) => {
122
109
  }
123
110
  })
124
111
 
125
- fastify.listen({ port: 0 }, function (err) {
126
- t.assert.ifError(err)
127
- t.after(() => fastify.close())
128
- sget({
129
- method: 'GET',
130
- url: 'http://localhost:' + fastify.server.address().port + '/this-would-404-without-url-rewrite'
131
- }, (err, response, body) => {
132
- t.assert.ifError(err)
133
- const parsedBody = JSON.parse(body)
134
- t.assert.deepStrictEqual(parsedBody, { hello: 'world', hostname: 'localhost', port: fastify.server.address().port })
135
- t.assert.strictEqual(response.statusCode, 200)
136
- done()
137
- })
138
- })
112
+ await fastify.listen({ port: 0 })
113
+ const port = fastify.server.address().port
114
+
115
+ t.after(() => fastify.close())
116
+
117
+ const result = await fetch(`http://localhost:${port}/this-would-404-without-url-rewrite`)
118
+
119
+ t.assert.ok(result.ok)
120
+ t.assert.strictEqual(result.status, 200)
121
+ t.assert.deepStrictEqual(await result.json(), { hello: 'world', hostname: 'localhost', port })
139
122
  })
@@ -2,10 +2,9 @@
2
2
 
3
3
  const { test } = require('node:test')
4
4
  const Fastify = require('..')
5
- const sget = require('simple-get').concat
6
5
 
7
- test('use semicolon delimiter default false', (t, done) => {
8
- t.plan(4)
6
+ test('use semicolon delimiter default false', async (t) => {
7
+ t.plan(2)
9
8
 
10
9
  const fastify = Fastify()
11
10
 
@@ -13,23 +12,19 @@ test('use semicolon delimiter default false', (t, done) => {
13
12
  reply.send(req.query)
14
13
  })
15
14
 
16
- fastify.listen({ port: 0 }, err => {
17
- t.assert.ifError(err)
18
- sget({
19
- method: 'GET',
20
- url: 'http://localhost:' + fastify.server.address().port + '/1234;foo=bar'
21
- }, (err, response, body) => {
22
- t.assert.ifError(err)
23
- t.assert.strictEqual(response.statusCode, 200)
24
- t.assert.deepStrictEqual(JSON.parse(body), {})
25
- fastify.close()
26
- done()
27
- })
15
+ const fastifyServer = await fastify.listen({ port: 0 })
16
+ t.after(() => { fastify.close() })
17
+
18
+ const result = await fetch(fastifyServer + '/1234;foo=bar', {
19
+ method: 'GET'
28
20
  })
21
+ t.assert.strictEqual(result.status, 200)
22
+ const body = await result.json()
23
+ t.assert.deepStrictEqual(body, {})
29
24
  })
30
25
 
31
- test('use semicolon delimiter set to true', (t, done) => {
32
- t.plan(4)
26
+ test('use semicolon delimiter set to true', async (t) => {
27
+ t.plan(3)
33
28
  const fastify = Fastify({
34
29
  useSemicolonDelimiter: true
35
30
  })
@@ -38,26 +33,19 @@ test('use semicolon delimiter set to true', (t, done) => {
38
33
  reply.send(req.query)
39
34
  })
40
35
 
41
- fastify.listen({ port: 0 }, err => {
42
- t.assert.ifError(err)
36
+ const fastifyServer = await fastify.listen({ port: 0 })
37
+ t.after(() => { fastify.close() })
43
38
 
44
- sget({
45
- method: 'GET',
46
- url: 'http://localhost:' + fastify.server.address().port + '/1234;foo=bar'
47
- }, (err, response, body) => {
48
- t.assert.ifError(err)
49
- t.assert.strictEqual(response.statusCode, 200)
50
- t.assert.deepStrictEqual(JSON.parse(body), {
51
- foo: 'bar'
52
- })
53
- fastify.close()
54
- done()
55
- })
39
+ const result = await fetch(fastifyServer + '/1234;foo=bar')
40
+ t.assert.ok(result.ok)
41
+ t.assert.strictEqual(result.status, 200)
42
+ t.assert.deepStrictEqual(await result.json(), {
43
+ foo: 'bar'
56
44
  })
57
45
  })
58
46
 
59
- test('use semicolon delimiter set to false', (t, done) => {
60
- t.plan(4)
47
+ test('use semicolon delimiter set to false', async (t) => {
48
+ t.plan(3)
61
49
 
62
50
  const fastify = Fastify({
63
51
  useSemicolonDelimiter: false
@@ -67,24 +55,17 @@ test('use semicolon delimiter set to false', (t, done) => {
67
55
  reply.send(req.query)
68
56
  })
69
57
 
70
- fastify.listen({ port: 0 }, err => {
71
- t.assert.ifError(err)
58
+ const fastifyServer = await fastify.listen({ port: 0 })
59
+ t.after(() => { fastify.close() })
72
60
 
73
- sget({
74
- method: 'GET',
75
- url: 'http://localhost:' + fastify.server.address().port + '/1234;foo=bar'
76
- }, (err, response, body) => {
77
- t.assert.ifError(err)
78
- t.assert.strictEqual(response.statusCode, 200)
79
- t.assert.deepStrictEqual(JSON.parse(body), {})
80
- fastify.close()
81
- done()
82
- })
83
- })
61
+ const result = await fetch(fastifyServer + '/1234;foo=bar')
62
+ t.assert.ok(result.ok)
63
+ t.assert.strictEqual(result.status, 200)
64
+ t.assert.deepStrictEqual(await result.json(), {})
84
65
  })
85
66
 
86
- test('use semicolon delimiter set to false return 404', (t, done) => {
87
- t.plan(3)
67
+ test('use semicolon delimiter set to false return 404', async (t) => {
68
+ t.plan(2)
88
69
 
89
70
  const fastify = Fastify({
90
71
  useSemicolonDelimiter: false
@@ -94,17 +75,94 @@ test('use semicolon delimiter set to false return 404', (t, done) => {
94
75
  reply.send(req.query)
95
76
  })
96
77
 
97
- fastify.listen({ port: 0 }, err => {
98
- t.assert.ifError(err)
78
+ const fastifyServer = await fastify.listen({ port: 0 })
79
+ t.after(() => { fastify.close() })
80
+
81
+ const result = await fetch(fastifyServer + '/1234;foo=bar')
82
+ t.assert.ok(!result.ok)
83
+ t.assert.strictEqual(result.status, 404)
84
+ })
99
85
 
100
- sget({
101
- method: 'GET',
102
- url: 'http://localhost:' + fastify.server.address().port + '/1234;foo=bar'
103
- }, (err, response, body) => {
104
- t.assert.ifError(err)
105
- t.assert.strictEqual(response.statusCode, 404)
106
- fastify.close()
107
- done()
108
- })
86
+ test('use routerOptions semicolon delimiter default false', async t => {
87
+ t.plan(3)
88
+
89
+ const fastify = Fastify()
90
+
91
+ fastify.get('/1234;foo=bar', (req, reply) => {
92
+ reply.send(req.query)
109
93
  })
94
+
95
+ const fastifyServer = await fastify.listen({ port: 0 })
96
+ t.after(() => { fastify.close() })
97
+
98
+ const result = await fetch(fastifyServer + '/1234;foo=bar')
99
+ t.assert.ok(result.ok)
100
+ t.assert.strictEqual(result.status, 200)
101
+ t.assert.deepStrictEqual(await result.json(), {})
102
+ })
103
+
104
+ test('use routerOptions semicolon delimiter set to true', async t => {
105
+ t.plan(3)
106
+ const fastify = Fastify({
107
+ routerOptions: {
108
+ useSemicolonDelimiter: true
109
+ }
110
+ })
111
+
112
+ fastify.get('/1234', async (req, reply) => {
113
+ reply.send(req.query)
114
+ })
115
+
116
+ const fastifyServer = await fastify.listen({ port: 0 })
117
+ t.after(() => { fastify.close() })
118
+
119
+ const result = await fetch(fastifyServer + '/1234;foo=bar')
120
+ t.assert.ok(result.ok)
121
+ t.assert.strictEqual(result.status, 200)
122
+ t.assert.deepStrictEqual(await result.json(), {
123
+ foo: 'bar'
124
+ })
125
+ })
126
+
127
+ test('use routerOptions semicolon delimiter set to false', async t => {
128
+ t.plan(3)
129
+
130
+ const fastify = Fastify({
131
+ routerOptions: {
132
+ useSemicolonDelimiter: false
133
+ }
134
+ })
135
+
136
+ fastify.get('/1234;foo=bar', (req, reply) => {
137
+ reply.send(req.query)
138
+ })
139
+
140
+ const fastifyServer = await fastify.listen({ port: 0 })
141
+ t.after(() => { fastify.close() })
142
+
143
+ const result = await fetch(fastifyServer + '/1234;foo=bar')
144
+ t.assert.ok(result.ok)
145
+ t.assert.strictEqual(result.status, 200)
146
+ t.assert.deepStrictEqual(await result.json(), {})
147
+ })
148
+
149
+ test('use routerOptions semicolon delimiter set to false return 404', async t => {
150
+ t.plan(2)
151
+
152
+ const fastify = Fastify({
153
+ routerOptions: {
154
+ useSemicolonDelimiter: false
155
+ }
156
+ })
157
+
158
+ fastify.get('/1234', (req, reply) => {
159
+ reply.send(req.query)
160
+ })
161
+
162
+ const fastifyServer = await fastify.listen({ port: 0 })
163
+ t.after(() => { fastify.close() })
164
+
165
+ const result = await fetch(fastifyServer + '/1234;foo=bar')
166
+ t.assert.ok(!result.ok)
167
+ t.assert.strictEqual(result.status, 404)
110
168
  })
@@ -3,7 +3,6 @@
3
3
  const { test, before } = require('node:test')
4
4
  const helper = require('./helper')
5
5
  const Fastify = require('..')
6
- const sget = require('simple-get').concat
7
6
  const http = require('node:http')
8
7
  const split = require('split2')
9
8
  const append = require('vary').append
@@ -233,8 +232,8 @@ test('Versioned route but not version header should return a 404', (t, done) =>
233
232
  })
234
233
  })
235
234
 
236
- test('Should register a versioned route (server)', (t, done) => {
237
- t.plan(6)
235
+ test('Should register a versioned route (server)', async t => {
236
+ t.plan(5)
238
237
  const fastify = Fastify()
239
238
 
240
239
  fastify.route({
@@ -246,34 +245,27 @@ test('Should register a versioned route (server)', (t, done) => {
246
245
  }
247
246
  })
248
247
 
249
- fastify.listen({ port: 0 }, err => {
250
- t.assert.ifError(err)
251
- t.after(() => { fastify.close() })
248
+ const fastifyServer = await fastify.listen({ port: 0 })
249
+ t.after(() => { fastify.close() })
252
250
 
253
- sget({
254
- method: 'GET',
255
- url: 'http://localhost:' + fastify.server.address().port,
256
- headers: {
257
- 'Accept-Version': '1.x'
258
- }
259
- }, (err, response, body) => {
260
- t.assert.ifError(err)
261
- t.assert.strictEqual(response.statusCode, 200)
262
- t.assert.deepStrictEqual(JSON.parse(body), { hello: 'world' })
263
-
264
- sget({
265
- method: 'GET',
266
- url: 'http://localhost:' + fastify.server.address().port,
267
- headers: {
268
- 'Accept-Version': '2.x'
269
- }
270
- }, (err, response, body) => {
271
- t.assert.ifError(err)
272
- t.assert.strictEqual(response.statusCode, 404)
273
- done()
274
- })
275
- })
251
+ const result1 = await fetch(fastifyServer, {
252
+ headers: {
253
+ 'Accept-Version': '1.x'
254
+ }
255
+ })
256
+ t.assert.ok(result1.ok)
257
+ t.assert.strictEqual(result1.status, 200)
258
+ const body1 = await result1.json()
259
+ t.assert.deepStrictEqual(body1, { hello: 'world' })
260
+
261
+ const result2 = await fetch(fastifyServer, {
262
+ headers: {
263
+ 'Accept-Version': '2.x'
264
+ }
276
265
  })
266
+
267
+ t.assert.ok(!result2.ok)
268
+ t.assert.strictEqual(result2.status, 404)
277
269
  })
278
270
 
279
271
  test('Shorthand route declaration', (t, done) => {
@@ -402,8 +394,8 @@ test('Bad accept version (inject)', (t, done) => {
402
394
  })
403
395
  })
404
396
 
405
- test('Bad accept version (server)', (t, done) => {
406
- t.plan(5)
397
+ test('Bad accept version (server)', async t => {
398
+ t.plan(4)
407
399
  const fastify = Fastify()
408
400
 
409
401
  fastify.route({
@@ -415,33 +407,24 @@ test('Bad accept version (server)', (t, done) => {
415
407
  }
416
408
  })
417
409
 
418
- fastify.listen({ port: 0 }, err => {
419
- t.assert.ifError(err)
420
- t.after(() => { fastify.close() })
410
+ const fastifyServer = await fastify.listen({ port: 0 })
411
+ t.after(() => { fastify.close() })
421
412
 
422
- sget({
423
- method: 'GET',
424
- url: 'http://localhost:' + fastify.server.address().port,
425
- headers: {
426
- 'Accept-Version': 'a.b.c'
427
- }
428
- }, (err, response, body) => {
429
- t.assert.ifError(err)
430
- t.assert.strictEqual(response.statusCode, 404)
431
-
432
- sget({
433
- method: 'GET',
434
- url: 'http://localhost:' + fastify.server.address().port,
435
- headers: {
436
- 'Accept-Version': 12
437
- }
438
- }, (err, response, body) => {
439
- t.assert.ifError(err)
440
- t.assert.strictEqual(response.statusCode, 404)
441
- done()
442
- })
443
- })
413
+ const result1 = await fetch(fastifyServer, {
414
+ headers: {
415
+ 'Accept-Version': 'a.b.c'
416
+ }
417
+ })
418
+ t.assert.ok(!result1.ok)
419
+ t.assert.strictEqual(result1.status, 404)
420
+
421
+ const result2 = await fetch(fastifyServer, {
422
+ headers: {
423
+ 'Accept-Version': '12'
424
+ }
444
425
  })
426
+ t.assert.ok(!result2.ok)
427
+ t.assert.strictEqual(result2.status, 404)
445
428
  })
446
429
 
447
430
  test('test log stream', (t, done) => {
package/types/errors.d.ts CHANGED
@@ -9,6 +9,9 @@ export type FastifyErrorCodes = Record<
9
9
  'FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_OBJ' |
10
10
  'FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_ARR' |
11
11
  'FST_ERR_VALIDATION' |
12
+ 'FST_ERR_LISTEN_OPTIONS_INVALID' |
13
+ 'FST_ERR_ERROR_HANDLER_NOT_FN' |
14
+ 'FST_ERR_ERROR_HANDLER_ALREADY_SET' |
12
15
  'FST_ERR_CTP_ALREADY_PRESENT' |
13
16
  'FST_ERR_CTP_INVALID_TYPE' |
14
17
  'FST_ERR_CTP_EMPTY_TYPE' |
@@ -18,12 +21,14 @@ export type FastifyErrorCodes = Record<
18
21
  'FST_ERR_CTP_INVALID_MEDIA_TYPE' |
19
22
  'FST_ERR_CTP_INVALID_CONTENT_LENGTH' |
20
23
  'FST_ERR_CTP_EMPTY_JSON_BODY' |
24
+ 'FST_ERR_CTP_INVALID_JSON_BODY' |
21
25
  'FST_ERR_CTP_INSTANCE_ALREADY_STARTED' |
22
26
  'FST_ERR_DEC_ALREADY_PRESENT' |
23
27
  'FST_ERR_DEC_DEPENDENCY_INVALID_TYPE' |
24
28
  'FST_ERR_DEC_MISSING_DEPENDENCY' |
25
29
  'FST_ERR_DEC_AFTER_START' |
26
30
  'FST_ERR_DEC_REFERENCE_TYPE' |
31
+ 'FST_ERR_DEC_UNDECLARED' |
27
32
  'FST_ERR_HOOK_INVALID_TYPE' |
28
33
  'FST_ERR_HOOK_INVALID_HANDLER' |
29
34
  'FST_ERR_HOOK_INVALID_ASYNC_HANDLER' |
@@ -32,7 +37,12 @@ export type FastifyErrorCodes = Record<
32
37
  'FST_ERR_HOOK_TIMEOUT' |
33
38
  'FST_ERR_LOG_INVALID_DESTINATION' |
34
39
  'FST_ERR_LOG_INVALID_LOGGER' |
40
+ 'FST_ERR_LOG_INVALID_LOGGER_INSTANCE' |
41
+ 'FST_ERR_LOG_INVALID_LOGGER_CONFIG' |
42
+ 'FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED' |
35
43
  'FST_ERR_REP_INVALID_PAYLOAD_TYPE' |
44
+ 'FST_ERR_REP_RESPONSE_BODY_CONSUMED' |
45
+ 'FST_ERR_REP_READABLE_STREAM_LOCKED' |
36
46
  'FST_ERR_REP_ALREADY_SENT' |
37
47
  'FST_ERR_REP_SENT_VALUE' |
38
48
  'FST_ERR_SEND_INSIDE_ONERR' |
@@ -56,7 +66,6 @@ export type FastifyErrorCodes = Record<
56
66
  'FST_ERR_DUPLICATED_ROUTE' |
57
67
  'FST_ERR_BAD_URL' |
58
68
  'FST_ERR_ASYNC_CONSTRAINT' |
59
- 'FST_ERR_DEFAULT_ROUTE_INVALID_TYPE' |
60
69
  'FST_ERR_INVALID_URL' |
61
70
  'FST_ERR_ROUTE_OPTIONS_NOT_OBJ' |
62
71
  'FST_ERR_ROUTE_DUPLICATED_HANDLER' |
@@ -72,6 +81,7 @@ export type FastifyErrorCodes = Record<
72
81
  'FST_ERR_INSTANCE_ALREADY_LISTENING' |
73
82
  'FST_ERR_PLUGIN_VERSION_MISMATCH' |
74
83
  'FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE' |
84
+ 'FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER' |
75
85
  'FST_ERR_PLUGIN_CALLBACK_NOT_FN' |
76
86
  'FST_ERR_PLUGIN_NOT_VALID' |
77
87
  'FST_ERR_ROOT_PLG_BOOTED' |
package/types/hooks.d.ts CHANGED
@@ -498,7 +498,7 @@ export type onTimeoutMetaHookHandler<
498
498
  /**
499
499
  * This hook is useful if you need to do some custom error logging or add some specific header in case of error.
500
500
  * It is not intended for changing the error, and calling reply.send will throw an exception.
501
- * This hook will be executed only after the customErrorHandler has been executed, and only if the customErrorHandler sends an error back to the user (Note that the default customErrorHandler always sends the error back to the user).
501
+ * This hook will be executed before the customErrorHandler.
502
502
  * Notice: unlike the other hooks, pass an error to the done function is not supported.
503
503
  */
504
504
  export interface onErrorHookHandler<
@@ -466,7 +466,7 @@ export interface FastifyInstance<
466
466
  errorHandler: (error: FastifyError, request: FastifyRequest, reply: FastifyReply) => void;
467
467
 
468
468
  /**
469
- * Set a function that will be called whenever an error happens
469
+ * Set a function that will be invoked whenever an exception is thrown during the request lifecycle.
470
470
  */
471
471
  setErrorHandler<TError extends Error = FastifyError, RouteGeneric extends RouteGenericInterface = RouteGenericInterface, SchemaCompiler extends FastifySchema = FastifySchema, TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault>(
472
472
  handler: (this: FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider>, error: TError, request: FastifyRequest<RouteGeneric, RawServer, RawRequest, SchemaCompiler, TypeProvider>, reply: FastifyReply<RouteGeneric, RawServer, RawRequest, RawReply, ContextConfigDefault, SchemaCompiler, TypeProvider>) => any | Promise<any>
package/types/reply.d.ts CHANGED
@@ -46,8 +46,8 @@ export interface FastifyReply<
46
46
  log: FastifyBaseLogger;
47
47
  request: FastifyRequest<RouteGeneric, RawServer, RawRequest, SchemaCompiler, TypeProvider>;
48
48
  server: FastifyInstance;
49
- code<Code extends ReplyKeysToCodes<keyof RouteGeneric['Reply']>>(statusCode: Code): FastifyReply<RouteGeneric, RawServer, RawRequest, RawReply, ContextConfig, SchemaCompiler, TypeProvider, ResolveReplyTypeWithRouteGeneric<RouteGeneric['Reply'], Code, SchemaCompiler, TypeProvider>>;
50
- status<Code extends ReplyKeysToCodes<keyof RouteGeneric['Reply']>>(statusCode: Code): FastifyReply<RouteGeneric, RawServer, RawRequest, RawReply, ContextConfig, SchemaCompiler, TypeProvider, ResolveReplyTypeWithRouteGeneric<RouteGeneric['Reply'], Code, SchemaCompiler, TypeProvider>>;
49
+ code<Code extends keyof SchemaCompiler['response'] extends never ? ReplyKeysToCodes<keyof RouteGeneric['Reply']> : keyof SchemaCompiler['response'] extends ReplyKeysToCodes<keyof RouteGeneric['Reply']> ? keyof SchemaCompiler['response'] : ReplyKeysToCodes<keyof RouteGeneric['Reply']>>(statusCode: Code): FastifyReply<RouteGeneric, RawServer, RawRequest, RawReply, ContextConfig, SchemaCompiler, TypeProvider, ResolveReplyTypeWithRouteGeneric<RouteGeneric['Reply'], Code, SchemaCompiler, TypeProvider>>;
50
+ status<Code extends keyof SchemaCompiler['response'] extends never ? ReplyKeysToCodes<keyof RouteGeneric['Reply']> : keyof SchemaCompiler['response'] extends ReplyKeysToCodes<keyof RouteGeneric['Reply']> ? keyof SchemaCompiler['response'] : ReplyKeysToCodes<keyof RouteGeneric['Reply']>>(statusCode: Code): FastifyReply<RouteGeneric, RawServer, RawRequest, RawReply, ContextConfig, SchemaCompiler, TypeProvider, ResolveReplyTypeWithRouteGeneric<RouteGeneric['Reply'], Code, SchemaCompiler, TypeProvider>>;
51
51
  statusCode: number;
52
52
  sent: boolean;
53
53
  send(payload?: ReplyType): FastifyReply<RouteGeneric, RawServer, RawRequest, RawReply, ContextConfig, SchemaCompiler, TypeProvider>;
@@ -32,6 +32,7 @@ export interface RequestRouteOptions<ContextConfig = ContextConfigDefault, Schem
32
32
  config: FastifyContextConfig & FastifyRouteConfig & ContextConfig;
33
33
  schema?: SchemaCompiler; // it is empty for 404 requests
34
34
  handler: RouteHandlerMethod;
35
+ version?: string;
35
36
  }
36
37
 
37
38
  /**
package/.taprc DELETED
@@ -1,7 +0,0 @@
1
- # vim: set filetype=yaml :
2
- node-arg:
3
- - '--allow-natives-syntax'
4
-
5
- include:
6
- - 'test/**/*.test.js'
7
- - 'test/**/*.test.mjs'