fastify 5.2.0 → 5.2.2
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.
- package/LICENSE +1 -1
- package/PROJECT_CHARTER.md +7 -7
- package/README.md +65 -67
- package/SPONSORS.md +2 -0
- package/build/build-validation.js +1 -1
- package/docs/Guides/Benchmarking.md +4 -4
- package/docs/Guides/Database.md +1 -1
- package/docs/Guides/Delay-Accepting-Requests.md +10 -10
- package/docs/Guides/Ecosystem.md +5 -1
- package/docs/Guides/Fluent-Schema.md +1 -1
- package/docs/Guides/Getting-Started.md +9 -5
- package/docs/Guides/Index.md +1 -1
- package/docs/Guides/Migration-Guide-V4.md +1 -1
- package/docs/Guides/Migration-Guide-V5.md +12 -2
- package/docs/Guides/Plugins-Guide.md +6 -6
- package/docs/Guides/Serverless.md +14 -48
- package/docs/Guides/Style-Guide.md +2 -2
- package/docs/Guides/Testing.md +2 -2
- package/docs/Guides/Write-Plugin.md +2 -3
- package/docs/Reference/ContentTypeParser.md +58 -78
- package/docs/Reference/Decorators.md +50 -60
- package/docs/Reference/Encapsulation.md +28 -33
- package/docs/Reference/Errors.md +52 -53
- package/docs/Reference/HTTP2.md +7 -7
- package/docs/Reference/Hooks.md +31 -30
- package/docs/Reference/LTS.md +10 -15
- package/docs/Reference/Lifecycle.md +19 -24
- package/docs/Reference/Logging.md +59 -56
- package/docs/Reference/Middleware.md +19 -19
- package/docs/Reference/Plugins.md +55 -71
- package/docs/Reference/Principles.md +25 -30
- package/docs/Reference/Reply.md +11 -10
- package/docs/Reference/Request.md +89 -99
- package/docs/Reference/Routes.md +108 -128
- package/docs/Reference/Server.md +19 -17
- package/docs/Reference/Type-Providers.md +19 -21
- package/docs/Reference/TypeScript.md +1 -18
- package/docs/Reference/Validation-and-Serialization.md +134 -159
- package/docs/Reference/Warnings.md +22 -25
- package/fastify.js +1 -1
- package/lib/contentTypeParser.js +7 -8
- package/lib/error-handler.js +14 -12
- package/lib/errors.js +4 -0
- package/lib/headRoute.js +4 -2
- package/lib/pluginUtils.js +4 -2
- package/lib/reply.js +4 -0
- package/lib/request.js +13 -9
- package/lib/server.js +5 -0
- package/lib/validation.js +1 -1
- package/lib/warnings.js +9 -0
- package/lib/wrapThenable.js +8 -1
- package/package.json +28 -17
- package/test/build/error-serializer.test.js +2 -1
- package/test/bundler/esbuild/package.json +1 -1
- package/test/close.test.js +125 -108
- package/test/custom-parser-async.test.js +34 -36
- package/test/custom-parser.2.test.js +19 -20
- package/test/custom-parser.3.test.js +56 -45
- package/test/delete.test.js +79 -67
- package/test/genReqId.test.js +125 -174
- package/test/has-route.test.js +1 -3
- package/test/internals/content-type-parser.test.js +1 -1
- package/test/internals/errors.test.js +19 -7
- package/test/issue-4959.test.js +84 -0
- package/test/listen.1.test.js +37 -34
- package/test/listen.2.test.js +47 -40
- package/test/listen.3.test.js +28 -32
- package/test/listen.4.test.js +61 -45
- package/test/listen.5.test.js +23 -0
- package/test/nullable-validation.test.js +30 -27
- package/test/register.test.js +55 -50
- package/test/request-error.test.js +114 -94
- package/test/route-shorthand.test.js +36 -32
- package/test/server.test.js +0 -175
- package/test/stream.5.test.js +35 -33
- package/test/throw.test.js +87 -91
- package/test/toolkit.js +32 -0
- package/test/trust-proxy.test.js +23 -23
- package/test/types/instance.test-d.ts +1 -0
- package/test/upgrade.test.js +32 -30
- package/test/web-api.test.js +44 -0
- package/types/instance.d.ts +4 -0
- package/test/test-reporter.mjs +0 -68
package/test/server.test.js
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const { test } = require('node:test')
|
|
4
4
|
const Fastify = require('..')
|
|
5
|
-
const sget = require('simple-get').concat
|
|
6
|
-
const undici = require('undici')
|
|
7
5
|
|
|
8
6
|
test('listen should accept null port', async t => {
|
|
9
7
|
const fastify = Fastify()
|
|
@@ -13,176 +11,3 @@ test('listen should accept null port', async t => {
|
|
|
13
11
|
fastify.listen({ port: null })
|
|
14
12
|
)
|
|
15
13
|
})
|
|
16
|
-
|
|
17
|
-
test('listen should accept undefined port', async t => {
|
|
18
|
-
const fastify = Fastify()
|
|
19
|
-
t.after(() => fastify.close())
|
|
20
|
-
|
|
21
|
-
await t.assert.doesNotReject(
|
|
22
|
-
fastify.listen({ port: undefined })
|
|
23
|
-
)
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
test('listen should accept stringified number port', async t => {
|
|
27
|
-
const fastify = Fastify()
|
|
28
|
-
t.after(() => fastify.close())
|
|
29
|
-
|
|
30
|
-
await t.assert.doesNotReject(
|
|
31
|
-
fastify.listen({ port: '1234' })
|
|
32
|
-
)
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
test('listen should accept log text resolution function', async t => {
|
|
36
|
-
const fastify = Fastify()
|
|
37
|
-
t.after(() => fastify.close())
|
|
38
|
-
|
|
39
|
-
await t.assert.doesNotReject(
|
|
40
|
-
fastify.listen({
|
|
41
|
-
host: '127.0.0.1',
|
|
42
|
-
port: '1234',
|
|
43
|
-
listenTextResolver: (address) => {
|
|
44
|
-
t.assert.strictEqual(address, 'http://127.0.0.1:1234')
|
|
45
|
-
return 'hardcoded text'
|
|
46
|
-
}
|
|
47
|
-
})
|
|
48
|
-
)
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
test('listen should reject string port', async (t) => {
|
|
52
|
-
const fastify = Fastify()
|
|
53
|
-
t.after(() => fastify.close())
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
await fastify.listen({ port: 'hello-world' })
|
|
57
|
-
} catch (error) {
|
|
58
|
-
t.assert.strictEqual(error.code, 'ERR_SOCKET_BAD_PORT')
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
try {
|
|
62
|
-
await fastify.listen({ port: '1234hello' })
|
|
63
|
-
} catch (error) {
|
|
64
|
-
t.assert.strictEqual(error.code, 'ERR_SOCKET_BAD_PORT')
|
|
65
|
-
}
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
test('Test for hostname and port', (t, end) => {
|
|
69
|
-
const app = Fastify()
|
|
70
|
-
t.after(() => app.close())
|
|
71
|
-
app.get('/host', (req, res) => {
|
|
72
|
-
const host = 'localhost:8000'
|
|
73
|
-
t.assert.strictEqual(req.host, host)
|
|
74
|
-
t.assert.strictEqual(req.hostname, req.host.split(':')[0])
|
|
75
|
-
t.assert.strictEqual(req.port, Number(req.host.split(':')[1]))
|
|
76
|
-
res.send('ok')
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
app.listen({ port: 8000 }, () => {
|
|
80
|
-
sget('http://localhost:8000/host', () => { end() })
|
|
81
|
-
})
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
test('abort signal', async t => {
|
|
85
|
-
await t.test('listen should not start server', (t, end) => {
|
|
86
|
-
t.plan(2)
|
|
87
|
-
function onClose (instance, done) {
|
|
88
|
-
t.assert.strictEqual(instance, fastify)
|
|
89
|
-
done()
|
|
90
|
-
end()
|
|
91
|
-
}
|
|
92
|
-
const controller = new AbortController()
|
|
93
|
-
|
|
94
|
-
const fastify = Fastify()
|
|
95
|
-
fastify.addHook('onClose', onClose)
|
|
96
|
-
fastify.listen({ port: 1234, signal: controller.signal }, (err) => {
|
|
97
|
-
t.assert.ifError(err)
|
|
98
|
-
})
|
|
99
|
-
controller.abort()
|
|
100
|
-
t.assert.strictEqual(fastify.server.listening, false)
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
await t.test('listen should not start server if already aborted', (t, end) => {
|
|
104
|
-
t.plan(2)
|
|
105
|
-
function onClose (instance, done) {
|
|
106
|
-
t.assert.strictEqual(instance, fastify)
|
|
107
|
-
done()
|
|
108
|
-
end()
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const controller = new AbortController()
|
|
112
|
-
controller.abort()
|
|
113
|
-
const fastify = Fastify()
|
|
114
|
-
fastify.addHook('onClose', onClose)
|
|
115
|
-
fastify.listen({ port: 1234, signal: controller.signal }, (err) => {
|
|
116
|
-
t.assert.ifError(err)
|
|
117
|
-
})
|
|
118
|
-
t.assert.strictEqual(fastify.server.listening, false)
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
await t.test('listen should throw if received invalid signal', t => {
|
|
122
|
-
t.plan(2)
|
|
123
|
-
const fastify = Fastify()
|
|
124
|
-
|
|
125
|
-
try {
|
|
126
|
-
fastify.listen({ port: 1234, signal: {} }, (err) => {
|
|
127
|
-
t.assert.ifError(err)
|
|
128
|
-
})
|
|
129
|
-
t.assert.fail('should throw')
|
|
130
|
-
} catch (e) {
|
|
131
|
-
t.assert.strictEqual(e.code, 'FST_ERR_LISTEN_OPTIONS_INVALID')
|
|
132
|
-
t.assert.strictEqual(e.message, 'Invalid listen options: \'Invalid options.signal\'')
|
|
133
|
-
}
|
|
134
|
-
})
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
test('#5180 - preClose should be called before closing secondary server', async (t) => {
|
|
138
|
-
t.plan(2)
|
|
139
|
-
const fastify = Fastify({ forceCloseConnections: true })
|
|
140
|
-
let flag = false
|
|
141
|
-
t.after(() => fastify.close())
|
|
142
|
-
|
|
143
|
-
fastify.addHook('preClose', () => {
|
|
144
|
-
flag = true
|
|
145
|
-
})
|
|
146
|
-
|
|
147
|
-
fastify.get('/', async (req, reply) => {
|
|
148
|
-
// request will be pending for 1 second to simulate a slow request
|
|
149
|
-
await new Promise((resolve) => { setTimeout(resolve, 1000) })
|
|
150
|
-
return { hello: 'world' }
|
|
151
|
-
})
|
|
152
|
-
|
|
153
|
-
fastify.listen({ port: 0 }, (err) => {
|
|
154
|
-
t.assert.ifError(err)
|
|
155
|
-
const addresses = fastify.addresses()
|
|
156
|
-
const mainServerAddress = fastify.server.address()
|
|
157
|
-
let secondaryAddress
|
|
158
|
-
for (const addr of addresses) {
|
|
159
|
-
if (addr.family !== mainServerAddress.family) {
|
|
160
|
-
secondaryAddress = addr
|
|
161
|
-
secondaryAddress.address = secondaryAddress.family === 'IPv6'
|
|
162
|
-
? `[${secondaryAddress.address}]`
|
|
163
|
-
: secondaryAddress.address
|
|
164
|
-
break
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (!secondaryAddress) {
|
|
169
|
-
t.assert.ok(true, 'Secondary address not found')
|
|
170
|
-
return
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
undici.request(`http://${secondaryAddress.address}:${secondaryAddress.port}/`)
|
|
174
|
-
.then(
|
|
175
|
-
() => { t.assert.fail('Request should not succeed') },
|
|
176
|
-
() => {
|
|
177
|
-
t.assert.ok(flag)
|
|
178
|
-
}
|
|
179
|
-
)
|
|
180
|
-
|
|
181
|
-
// Close the server while the slow request is pending
|
|
182
|
-
setTimeout(fastify.close, 250)
|
|
183
|
-
})
|
|
184
|
-
|
|
185
|
-
// Wait 1000ms to ensure that the test is finished and async operations are
|
|
186
|
-
// completed
|
|
187
|
-
await new Promise((resolve) => { setTimeout(resolve, 1000) })
|
|
188
|
-
})
|
package/test/stream.5.test.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const test = t.test
|
|
3
|
+
const { test } = require('node:test')
|
|
5
4
|
const proxyquire = require('proxyquire')
|
|
6
5
|
const fs = require('node:fs')
|
|
7
6
|
const Readable = require('node:stream').Readable
|
|
8
7
|
const sget = require('simple-get').concat
|
|
9
8
|
const Fastify = require('..')
|
|
10
9
|
|
|
11
|
-
test('should destroy stream when response is ended', t => {
|
|
10
|
+
test('should destroy stream when response is ended', (t, done) => {
|
|
12
11
|
t.plan(4)
|
|
13
12
|
const stream = require('node:stream')
|
|
14
13
|
const fastify = Fastify()
|
|
@@ -17,7 +16,7 @@ test('should destroy stream when response is ended', t => {
|
|
|
17
16
|
const reallyLongStream = new stream.Readable({
|
|
18
17
|
read: function () { },
|
|
19
18
|
destroy: function (err, callback) {
|
|
20
|
-
t.ok('called')
|
|
19
|
+
t.assert.ok('called')
|
|
21
20
|
callback(err)
|
|
22
21
|
}
|
|
23
22
|
})
|
|
@@ -26,23 +25,25 @@ test('should destroy stream when response is ended', t => {
|
|
|
26
25
|
})
|
|
27
26
|
|
|
28
27
|
fastify.listen({ port: 0 }, err => {
|
|
29
|
-
t.
|
|
30
|
-
t.
|
|
28
|
+
t.assert.ifError(err)
|
|
29
|
+
t.after(() => fastify.close())
|
|
31
30
|
|
|
32
31
|
sget(`http://localhost:${fastify.server.address().port}/error`, function (err, response) {
|
|
33
|
-
t.
|
|
34
|
-
t.
|
|
32
|
+
t.assert.ifError(err)
|
|
33
|
+
t.assert.strictEqual(response.statusCode, 200)
|
|
34
|
+
done()
|
|
35
35
|
})
|
|
36
36
|
})
|
|
37
37
|
})
|
|
38
38
|
|
|
39
|
-
test('should mark reply as sent before pumping the payload stream into response for async route handler', t => {
|
|
39
|
+
test('should mark reply as sent before pumping the payload stream into response for async route handler', (t, done) => {
|
|
40
40
|
t.plan(3)
|
|
41
|
+
t.after(() => fastify.close())
|
|
41
42
|
|
|
42
43
|
const handleRequest = proxyquire('../lib/handleRequest', {
|
|
43
44
|
'./wrapThenable': (thenable, reply) => {
|
|
44
45
|
thenable.then(function (payload) {
|
|
45
|
-
t.
|
|
46
|
+
t.assert.strictEqual(reply.sent, true)
|
|
46
47
|
})
|
|
47
48
|
}
|
|
48
49
|
})
|
|
@@ -66,20 +67,20 @@ test('should mark reply as sent before pumping the payload stream into response
|
|
|
66
67
|
url: '/',
|
|
67
68
|
method: 'GET'
|
|
68
69
|
}, (err, res) => {
|
|
69
|
-
t.
|
|
70
|
-
t.
|
|
71
|
-
|
|
70
|
+
t.assert.ifError(err)
|
|
71
|
+
t.assert.strictEqual(res.payload, fs.readFileSync(__filename, 'utf8'))
|
|
72
|
+
done()
|
|
72
73
|
})
|
|
73
74
|
})
|
|
74
75
|
|
|
75
|
-
test('reply.send handles aborted requests', t => {
|
|
76
|
+
test('reply.send handles aborted requests', (t, done) => {
|
|
76
77
|
t.plan(2)
|
|
77
78
|
|
|
78
79
|
const spyLogger = {
|
|
79
80
|
level: 'error',
|
|
80
81
|
fatal: () => { },
|
|
81
82
|
error: () => {
|
|
82
|
-
t.fail('should not log an error')
|
|
83
|
+
t.assert.fail('should not log an error')
|
|
83
84
|
},
|
|
84
85
|
warn: () => { },
|
|
85
86
|
info: () => { },
|
|
@@ -103,31 +104,31 @@ test('reply.send handles aborted requests', t => {
|
|
|
103
104
|
})
|
|
104
105
|
|
|
105
106
|
fastify.listen({ port: 0 }, err => {
|
|
106
|
-
t.
|
|
107
|
-
t.
|
|
107
|
+
t.assert.ifError(err)
|
|
108
|
+
t.after(() => fastify.close())
|
|
108
109
|
|
|
109
110
|
const port = fastify.server.address().port
|
|
110
111
|
const http = require('node:http')
|
|
111
112
|
const req = http.get(`http://localhost:${port}`)
|
|
112
113
|
.on('error', (err) => {
|
|
113
|
-
t.
|
|
114
|
-
|
|
114
|
+
t.assert.strictEqual(err.code, 'ECONNRESET')
|
|
115
|
+
done()
|
|
115
116
|
})
|
|
116
117
|
|
|
117
118
|
setTimeout(() => {
|
|
118
|
-
req.
|
|
119
|
+
req.destroy()
|
|
119
120
|
}, 1)
|
|
120
121
|
})
|
|
121
122
|
})
|
|
122
123
|
|
|
123
|
-
test('request terminated should not crash fastify', t => {
|
|
124
|
+
test('request terminated should not crash fastify', (t, done) => {
|
|
124
125
|
t.plan(10)
|
|
125
126
|
|
|
126
127
|
const spyLogger = {
|
|
127
128
|
level: 'error',
|
|
128
129
|
fatal: () => { },
|
|
129
130
|
error: () => {
|
|
130
|
-
t.fail('should not log an error')
|
|
131
|
+
t.assert.fail('should not log an error')
|
|
131
132
|
},
|
|
132
133
|
warn: () => { },
|
|
133
134
|
info: () => { },
|
|
@@ -156,18 +157,18 @@ test('request terminated should not crash fastify', t => {
|
|
|
156
157
|
})
|
|
157
158
|
|
|
158
159
|
fastify.listen({ port: 0 }, err => {
|
|
159
|
-
t.
|
|
160
|
-
t.
|
|
160
|
+
t.assert.ifError(err)
|
|
161
|
+
t.after(() => fastify.close())
|
|
161
162
|
|
|
162
163
|
const port = fastify.server.address().port
|
|
163
164
|
const http = require('node:http')
|
|
164
165
|
const req = http.get(`http://localhost:${port}`, function (res) {
|
|
165
166
|
const { statusCode, headers } = res
|
|
166
|
-
t.
|
|
167
|
-
t.
|
|
168
|
-
t.
|
|
167
|
+
t.assert.strictEqual(statusCode, 200)
|
|
168
|
+
t.assert.strictEqual(headers['content-type'], 'text/html; charset=utf-8')
|
|
169
|
+
t.assert.strictEqual(headers['transfer-encoding'], 'chunked')
|
|
169
170
|
res.on('data', function (chunk) {
|
|
170
|
-
t.
|
|
171
|
+
t.assert.strictEqual(chunk.toString(), '<h1>HTML</h1>')
|
|
171
172
|
})
|
|
172
173
|
|
|
173
174
|
setTimeout(() => {
|
|
@@ -176,16 +177,17 @@ test('request terminated should not crash fastify', t => {
|
|
|
176
177
|
// the server is not crash, we can connect it
|
|
177
178
|
http.get(`http://localhost:${port}`, function (res) {
|
|
178
179
|
const { statusCode, headers } = res
|
|
179
|
-
t.
|
|
180
|
-
t.
|
|
181
|
-
t.
|
|
180
|
+
t.assert.strictEqual(statusCode, 200)
|
|
181
|
+
t.assert.strictEqual(headers['content-type'], 'text/html; charset=utf-8')
|
|
182
|
+
t.assert.strictEqual(headers['transfer-encoding'], 'chunked')
|
|
182
183
|
let payload = ''
|
|
183
184
|
res.on('data', function (chunk) {
|
|
184
185
|
payload += chunk.toString()
|
|
185
186
|
})
|
|
186
187
|
res.on('end', function () {
|
|
187
|
-
t.
|
|
188
|
-
t.
|
|
188
|
+
t.assert.strictEqual(payload, '<h1>HTML</h1><h1>should display on second stream</h1>')
|
|
189
|
+
t.assert.ok('should end properly')
|
|
190
|
+
done()
|
|
189
191
|
})
|
|
190
192
|
})
|
|
191
193
|
}, 1)
|