fastify 3.27.3 → 4.0.0-alpha.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/.taprc +3 -0
- package/README.md +7 -7
- package/build/build-error-serializer.js +27 -0
- package/build/build-validation.js +47 -35
- package/docs/Guides/Database.md +320 -0
- package/docs/Guides/Getting-Started.md +7 -7
- package/docs/Guides/Plugins-Guide.md +1 -1
- package/docs/Guides/Serverless.md +3 -3
- package/docs/Guides/Testing.md +2 -2
- package/docs/Migration-Guide-V4.md +12 -0
- package/docs/Reference/ContentTypeParser.md +4 -0
- package/docs/Reference/Decorators.md +2 -2
- package/docs/Reference/Encapsulation.md +2 -2
- package/docs/Reference/Errors.md +51 -6
- package/docs/Reference/HTTP2.md +3 -3
- package/docs/Reference/Hooks.md +4 -7
- package/docs/Reference/LTS.md +5 -4
- package/docs/Reference/Plugins.md +3 -3
- package/docs/Reference/Reply.md +23 -22
- package/docs/Reference/Request.md +1 -3
- package/docs/Reference/Routes.md +22 -15
- package/docs/Reference/Server.md +69 -119
- package/docs/Reference/TypeScript.md +20 -22
- package/docs/Reference/Validation-and-Serialization.md +30 -55
- package/docs/Type-Providers.md +257 -0
- package/examples/asyncawait.js +1 -1
- package/examples/benchmark/hooks-benchmark-async-await.js +1 -1
- package/examples/benchmark/hooks-benchmark.js +1 -1
- package/examples/benchmark/simple.js +1 -1
- package/examples/hooks.js +2 -2
- package/examples/http2.js +1 -1
- package/examples/https.js +1 -1
- package/examples/parser.js +1 -1
- package/examples/route-prefix.js +1 -1
- package/examples/shared-schema.js +1 -1
- package/examples/simple-stream.js +18 -0
- package/examples/simple.js +1 -1
- package/examples/simple.mjs +1 -1
- package/examples/typescript-server.ts +1 -1
- package/examples/use-plugin.js +1 -1
- package/fastify.d.ts +34 -22
- package/fastify.js +40 -36
- package/lib/configValidator.js +902 -1023
- package/lib/contentTypeParser.js +6 -16
- package/lib/context.js +36 -10
- package/lib/decorate.js +3 -1
- package/lib/error-handler.js +158 -0
- package/lib/error-serializer.js +257 -0
- package/lib/errors.js +43 -9
- package/lib/fourOhFour.js +31 -20
- package/lib/handleRequest.js +10 -13
- package/lib/hooks.js +14 -9
- package/lib/pluginOverride.js +0 -3
- package/lib/pluginUtils.js +3 -2
- package/lib/reply.js +29 -158
- package/lib/request.js +13 -10
- package/lib/route.js +131 -138
- package/lib/schema-controller.js +2 -2
- package/lib/schemas.js +27 -1
- package/lib/server.js +241 -116
- package/lib/symbols.js +4 -3
- package/lib/validation.js +2 -1
- package/lib/warnings.js +4 -12
- package/lib/wrapThenable.js +4 -11
- package/package.json +37 -39
- package/test/404s.test.js +258 -125
- package/test/500s.test.js +3 -3
- package/test/als.test.js +1 -1
- package/test/async-await.test.js +20 -76
- package/test/bodyLimit.test.js +1 -1
- package/test/build-certificate.js +6 -7
- package/test/case-insensitive.test.js +4 -4
- package/test/close-pipelining.test.js +2 -2
- package/test/close.test.js +11 -11
- package/test/content-parser.test.js +32 -0
- package/test/context-config.test.js +52 -0
- package/test/custom-http-server.test.js +14 -7
- package/test/custom-parser-async.test.js +1 -66
- package/test/custom-parser.test.js +92 -159
- package/test/custom-querystring-parser.test.js +3 -3
- package/test/decorator.test.js +11 -13
- package/test/delete.test.js +6 -6
- package/test/encapsulated-error-handler.test.js +50 -0
- package/test/esm/index.test.js +0 -14
- package/test/fastify-instance.test.js +4 -4
- package/test/fluent-schema.test.js +4 -4
- package/test/genReqId.test.js +1 -1
- package/test/get.test.js +4 -4
- package/test/handler-context.test.js +2 -2
- package/test/head.test.js +1 -1
- package/test/helper.js +19 -4
- package/test/hooks-async.test.js +15 -48
- package/test/hooks.on-ready.test.js +10 -5
- package/test/hooks.test.js +78 -119
- package/test/http2/closing.test.js +10 -16
- package/test/http2/constraint.test.js +1 -1
- package/test/http2/head.test.js +1 -1
- package/test/http2/plain.test.js +1 -1
- package/test/http2/secure-with-fallback.test.js +1 -1
- package/test/http2/secure.test.js +1 -1
- package/test/http2/unknown-http-method.test.js +4 -10
- package/test/https/custom-https-server.test.js +12 -6
- package/test/https/https.test.js +1 -1
- package/test/input-validation.js +3 -3
- package/test/internals/handleRequest.test.js +6 -43
- package/test/internals/initialConfig.test.js +41 -12
- package/test/internals/logger.test.js +2 -2
- package/test/internals/reply.test.js +281 -40
- package/test/internals/request.test.js +13 -7
- package/test/internals/server.test.js +88 -0
- package/test/listen.deprecated.test.js +202 -0
- package/test/listen.test.js +118 -150
- package/test/logger.test.js +82 -42
- package/test/maxRequestsPerSocket.test.js +8 -6
- package/test/middleware.test.js +2 -25
- package/test/nullable-validation.test.js +53 -16
- package/test/output-validation.test.js +1 -1
- package/test/plugin.test.js +47 -21
- package/test/pretty-print.test.js +22 -10
- package/test/promises.test.js +1 -1
- package/test/proto-poisoning.test.js +6 -6
- package/test/register.test.js +3 -3
- package/test/reply-error.test.js +126 -15
- package/test/request-error.test.js +3 -6
- package/test/route-hooks.test.js +18 -18
- package/test/route-prefix.test.js +2 -1
- package/test/route.test.js +206 -22
- package/test/router-options.test.js +2 -2
- package/test/schema-examples.test.js +11 -5
- package/test/schema-feature.test.js +25 -20
- package/test/schema-serialization.test.js +9 -9
- package/test/schema-special-usage.test.js +5 -153
- package/test/schema-validation.test.js +9 -9
- package/test/skip-reply-send.test.js +2 -2
- package/test/stream.test.js +82 -23
- package/test/throw.test.js +8 -5
- package/test/trust-proxy.test.js +6 -6
- package/test/type-provider.test.js +20 -0
- package/test/types/fastify.test-d.ts +10 -18
- package/test/types/import.js +2 -0
- package/test/types/import.ts +1 -0
- package/test/types/instance.test-d.ts +68 -17
- package/test/types/logger.test-d.ts +44 -15
- package/test/types/reply.test-d.ts +2 -1
- package/test/types/route.test-d.ts +8 -2
- package/test/types/schema.test-d.ts +2 -39
- package/test/types/type-provider.test-d.ts +417 -0
- package/test/url-rewriting.test.js +3 -3
- package/test/validation-error-handling.test.js +8 -8
- package/test/versioned-routes.test.js +30 -18
- package/test/wrapThenable.test.js +7 -6
- package/types/content-type-parser.d.ts +17 -8
- package/types/hooks.d.ts +102 -59
- package/types/instance.d.ts +244 -118
- package/types/logger.d.ts +18 -104
- package/types/plugin.d.ts +10 -4
- package/types/reply.d.ts +18 -12
- package/types/request.d.ts +10 -5
- package/types/route.d.ts +42 -31
- package/types/schema.d.ts +1 -1
- package/types/type-provider.d.ts +99 -0
- package/types/utils.d.ts +1 -1
- package/lib/schema-compilers.js +0 -12
- package/test/emit-warning.test.js +0 -166
package/lib/server.js
CHANGED
|
@@ -1,16 +1,213 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const assert = require('assert')
|
|
4
3
|
const http = require('http')
|
|
5
4
|
const https = require('https')
|
|
5
|
+
const dns = require('dns')
|
|
6
6
|
|
|
7
|
-
const
|
|
7
|
+
const warnings = require('./warnings')
|
|
8
|
+
const { kState, kOptions, kServerBindings } = require('./symbols')
|
|
8
9
|
const { FST_ERR_HTTP2_INVALID_VERSION, FST_ERR_REOPENED_CLOSE_SERVER, FST_ERR_REOPENED_SERVER } = require('./errors')
|
|
9
10
|
|
|
11
|
+
module.exports = createServer
|
|
12
|
+
|
|
10
13
|
function createServer (options, httpHandler) {
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
const server = getServerInstance(options, httpHandler)
|
|
15
|
+
|
|
16
|
+
return { server, listen }
|
|
17
|
+
|
|
18
|
+
// `this` is the Fastify object
|
|
19
|
+
function listen (listenOptions, ...args) {
|
|
20
|
+
let cb = args.slice(-1).pop()
|
|
21
|
+
// When the variadic signature deprecation is complete, the function
|
|
22
|
+
// declaration should become:
|
|
23
|
+
// function listen (listenOptions = { port: 0, host: 'localhost' }, cb = undefined)
|
|
24
|
+
// Upon doing so, the `normalizeListenArgs` function is no longer needed,
|
|
25
|
+
// and all of this preamble to feed it correctly also no longer needed.
|
|
26
|
+
const firstArgType = Object.prototype.toString.call(arguments[0])
|
|
27
|
+
if (arguments.length === 0) {
|
|
28
|
+
listenOptions = normalizeListenArgs([])
|
|
29
|
+
} else if (arguments.length > 0 && (firstArgType !== '[object Object]' && firstArgType !== '[object Function]')) {
|
|
30
|
+
warnings.emit('FSTDEP011')
|
|
31
|
+
listenOptions = normalizeListenArgs(Array.from(arguments))
|
|
32
|
+
cb = listenOptions.cb
|
|
33
|
+
} else if (args.length > 1) {
|
|
34
|
+
// `.listen(obj, a, ..., n, callback )`
|
|
35
|
+
warnings.emit('FSTDEP011')
|
|
36
|
+
// Deal with `.listen(port, host, backlog, [cb])`
|
|
37
|
+
const hostPath = listenOptions.path ? [listenOptions.path] : [listenOptions.port ?? 0, listenOptions.host ?? 'localhost']
|
|
38
|
+
Object.assign(listenOptions, normalizeListenArgs([...hostPath, ...args]))
|
|
39
|
+
} else {
|
|
40
|
+
listenOptions.cb = cb
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const { host = 'localhost' } = listenOptions
|
|
44
|
+
if (Object.prototype.hasOwnProperty.call(listenOptions, 'host') === false) {
|
|
45
|
+
listenOptions.host = host
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (host === 'localhost') {
|
|
49
|
+
listenOptions.cb = (err, address) => {
|
|
50
|
+
if (err) {
|
|
51
|
+
// the server did not start
|
|
52
|
+
cb(err, address)
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
multipleBindings.call(this, server, httpHandler, options, listenOptions, () => {
|
|
57
|
+
this[kState].listening = true
|
|
58
|
+
cb(null, address)
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// https://github.com/nodejs/node/issues/9390
|
|
64
|
+
// If listening to 'localhost', listen to both 127.0.0.1 or ::1 if they are available.
|
|
65
|
+
// If listening to 127.0.0.1, only listen to 127.0.0.1.
|
|
66
|
+
// If listening to ::1, only listen to ::1.
|
|
67
|
+
|
|
68
|
+
if (cb === undefined) {
|
|
69
|
+
const listening = listenPromise.call(this, server, listenOptions)
|
|
70
|
+
/* istanbul ignore else */
|
|
71
|
+
if (host === 'localhost') {
|
|
72
|
+
return listening.then(address => {
|
|
73
|
+
return new Promise((resolve, reject) => {
|
|
74
|
+
multipleBindings.call(this, server, httpHandler, options, listenOptions, () => {
|
|
75
|
+
this[kState].listening = true
|
|
76
|
+
resolve(address)
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
this.ready(listenCallback.call(this, server, listenOptions))
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function multipleBindings (mainServer, httpHandler, serverOpts, listenOptions, onListen) {
|
|
88
|
+
// the main server is started, we need to start the secondary servers
|
|
89
|
+
this[kState].listening = false
|
|
90
|
+
|
|
91
|
+
// let's check if we need to bind additional addresses
|
|
92
|
+
dns.lookup(listenOptions.host, { all: true }, (dnsErr, addresses) => {
|
|
93
|
+
if (dnsErr) {
|
|
94
|
+
// not blocking the main server listening
|
|
95
|
+
// this.log.warn('dns.lookup error:', dnsErr)
|
|
96
|
+
onListen()
|
|
97
|
+
return
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
let binding = 0
|
|
101
|
+
let binded = 0
|
|
102
|
+
const primaryAddress = mainServer.address()
|
|
103
|
+
for (const adr of addresses) {
|
|
104
|
+
if (adr.address !== primaryAddress.address) {
|
|
105
|
+
binding++
|
|
106
|
+
const secondaryOpts = Object.assign({}, listenOptions, {
|
|
107
|
+
host: adr.address,
|
|
108
|
+
port: primaryAddress.port,
|
|
109
|
+
cb: (_ignoreErr) => {
|
|
110
|
+
binded++
|
|
111
|
+
|
|
112
|
+
if (!_ignoreErr) {
|
|
113
|
+
this[kServerBindings].push(secondaryServer)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (binded === binding) {
|
|
117
|
+
// regardless of the error, we are done
|
|
118
|
+
onListen()
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
const secondaryServer = getServerInstance(serverOpts, httpHandler)
|
|
124
|
+
const closeSecondary = () => { secondaryServer.close(() => {}) }
|
|
125
|
+
mainServer.on('unref', closeSecondary)
|
|
126
|
+
mainServer.on('close', closeSecondary)
|
|
127
|
+
mainServer.on('error', closeSecondary)
|
|
128
|
+
listenCallback.call(this, secondaryServer, secondaryOpts)()
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// no extra bindings are necessary
|
|
133
|
+
if (binding === 0) {
|
|
134
|
+
onListen()
|
|
135
|
+
return
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// in test files we are using unref so we need to propagate the unref event
|
|
139
|
+
// to the secondary servers. It is valid only when the user is
|
|
140
|
+
// listening on localhost
|
|
141
|
+
const originUnref = mainServer.unref
|
|
142
|
+
/* istanbul ignore next */
|
|
143
|
+
mainServer.unref = function () {
|
|
144
|
+
originUnref.call(mainServer)
|
|
145
|
+
mainServer.emit('unref')
|
|
146
|
+
}
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function listenCallback (server, listenOptions) {
|
|
151
|
+
const wrap = (err) => {
|
|
152
|
+
server.removeListener('error', wrap)
|
|
153
|
+
if (!err) {
|
|
154
|
+
const address = logServerAddress.call(this, server)
|
|
155
|
+
listenOptions.cb(null, address)
|
|
156
|
+
} else {
|
|
157
|
+
this[kState].listening = false
|
|
158
|
+
listenOptions.cb(err, null)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return (err) => {
|
|
163
|
+
if (err != null) return listenOptions.cb(err)
|
|
164
|
+
|
|
165
|
+
if (this[kState].listening && this[kState].closing) {
|
|
166
|
+
return listenOptions.cb(new FST_ERR_REOPENED_CLOSE_SERVER(), null)
|
|
167
|
+
} else if (this[kState].listening) {
|
|
168
|
+
return listenOptions.cb(new FST_ERR_REOPENED_SERVER(), null)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
server.once('error', wrap)
|
|
172
|
+
server.listen(listenOptions, wrap)
|
|
173
|
+
|
|
174
|
+
this[kState].listening = true
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function listenPromise (server, listenOptions) {
|
|
179
|
+
if (this[kState].listening && this[kState].closing) {
|
|
180
|
+
return Promise.reject(new FST_ERR_REOPENED_CLOSE_SERVER())
|
|
181
|
+
} else if (this[kState].listening) {
|
|
182
|
+
return Promise.reject(new FST_ERR_REOPENED_SERVER())
|
|
183
|
+
}
|
|
13
184
|
|
|
185
|
+
return this.ready().then(() => {
|
|
186
|
+
let errEventHandler
|
|
187
|
+
const errEvent = new Promise((resolve, reject) => {
|
|
188
|
+
errEventHandler = (err) => {
|
|
189
|
+
this[kState].listening = false
|
|
190
|
+
reject(err)
|
|
191
|
+
}
|
|
192
|
+
server.once('error', errEventHandler)
|
|
193
|
+
})
|
|
194
|
+
const listen = new Promise((resolve, reject) => {
|
|
195
|
+
server.listen(listenOptions, () => {
|
|
196
|
+
server.removeListener('error', errEventHandler)
|
|
197
|
+
resolve(logServerAddress.call(this, server))
|
|
198
|
+
})
|
|
199
|
+
// we set it afterwards because listen can throw
|
|
200
|
+
this[kState].listening = true
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
return Promise.race([
|
|
204
|
+
errEvent, // e.g invalid port range error is always emitted before the server listening
|
|
205
|
+
listen
|
|
206
|
+
])
|
|
207
|
+
})
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function getServerInstance (options, httpHandler) {
|
|
14
211
|
let server = null
|
|
15
212
|
if (options.serverFactory) {
|
|
16
213
|
server = options.serverFactory(httpHandler, options)
|
|
@@ -41,123 +238,53 @@ function createServer (options, httpHandler) {
|
|
|
41
238
|
if (!options.serverFactory) {
|
|
42
239
|
server.setTimeout(options.connectionTimeout)
|
|
43
240
|
}
|
|
241
|
+
return server
|
|
242
|
+
}
|
|
44
243
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const normalizeListenArgs = (args) => {
|
|
50
|
-
if (args.length === 0) {
|
|
51
|
-
return { port: 0, host: 'localhost' }
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const cb = typeof args[args.length - 1] === 'function' ? args.pop() : undefined
|
|
55
|
-
const options = { cb }
|
|
56
|
-
|
|
57
|
-
const firstArg = args[0]
|
|
58
|
-
const argsLength = args.length
|
|
59
|
-
const lastArg = args[argsLength - 1]
|
|
60
|
-
/* Deal with listen (options) || (handle[, backlog]) */
|
|
61
|
-
if (typeof firstArg === 'object' && firstArg !== null) {
|
|
62
|
-
options.backlog = argsLength > 1 ? lastArg : undefined
|
|
63
|
-
Object.assign(options, firstArg)
|
|
64
|
-
} else if (typeof firstArg === 'string' && isNaN(firstArg)) {
|
|
65
|
-
/* Deal with listen (pipe[, backlog]) */
|
|
66
|
-
options.path = firstArg
|
|
67
|
-
options.backlog = argsLength > 1 ? lastArg : undefined
|
|
68
|
-
} else {
|
|
69
|
-
/* Deal with listen ([port[, host[, backlog]]]) */
|
|
70
|
-
options.port = argsLength >= 1 && firstArg ? firstArg : 0
|
|
71
|
-
// This will listen to what localhost is.
|
|
72
|
-
// It can be 127.0.0.1 or ::1, depending on the operating system.
|
|
73
|
-
// Fixes https://github.com/fastify/fastify/issues/1022.
|
|
74
|
-
options.host = argsLength >= 2 && args[1] ? args[1] : 'localhost'
|
|
75
|
-
options.backlog = argsLength >= 3 ? args[2] : undefined
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return options
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const listenOptions = normalizeListenArgs(Array.from(arguments))
|
|
82
|
-
const cb = listenOptions.cb
|
|
83
|
-
|
|
84
|
-
const wrap = err => {
|
|
85
|
-
server.removeListener('error', wrap)
|
|
86
|
-
if (!err) {
|
|
87
|
-
const address = logServerAddress()
|
|
88
|
-
cb(null, address)
|
|
89
|
-
} else {
|
|
90
|
-
this[kState].listening = false
|
|
91
|
-
cb(err, null)
|
|
92
|
-
}
|
|
93
|
-
}
|
|
244
|
+
function normalizeListenArgs (args) {
|
|
245
|
+
if (args.length === 0) {
|
|
246
|
+
return { port: 0, host: 'localhost' }
|
|
247
|
+
}
|
|
94
248
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
return Promise.reject(new FST_ERR_REOPENED_CLOSE_SERVER())
|
|
98
|
-
} else if (this[kState].listening) {
|
|
99
|
-
return Promise.reject(new FST_ERR_REOPENED_SERVER())
|
|
100
|
-
}
|
|
249
|
+
const cb = typeof args[args.length - 1] === 'function' ? args.pop() : undefined
|
|
250
|
+
const options = { cb }
|
|
101
251
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
})
|
|
252
|
+
const firstArg = args[0]
|
|
253
|
+
const argsLength = args.length
|
|
254
|
+
const lastArg = args[argsLength - 1]
|
|
255
|
+
if (typeof firstArg === 'string' && isNaN(firstArg)) {
|
|
256
|
+
/* Deal with listen (pipe[, backlog]) */
|
|
257
|
+
options.path = firstArg
|
|
258
|
+
options.backlog = argsLength > 1 ? lastArg : undefined
|
|
259
|
+
} else {
|
|
260
|
+
/* Deal with listen ([port[, host[, backlog]]]) */
|
|
261
|
+
options.port = argsLength >= 1 && Number.isInteger(firstArg) ? firstArg : 0
|
|
262
|
+
// This will listen to what localhost is.
|
|
263
|
+
// It can be 127.0.0.1 or ::1, depending on the operating system.
|
|
264
|
+
// Fixes https://github.com/fastify/fastify/issues/1022.
|
|
265
|
+
options.host = argsLength >= 2 && args[1] ? args[1] : 'localhost'
|
|
266
|
+
options.backlog = argsLength >= 3 ? args[2] : undefined
|
|
267
|
+
}
|
|
119
268
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
listen
|
|
123
|
-
])
|
|
124
|
-
})
|
|
125
|
-
}
|
|
269
|
+
return options
|
|
270
|
+
}
|
|
126
271
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
/* istanbul ignore next */
|
|
139
|
-
address = (isUnixSocket ? '' : ('http' + (this[kOptions].https ? 's' : '') + '://')) + address
|
|
140
|
-
this.log.info('Server listening at ' + address)
|
|
141
|
-
return address
|
|
272
|
+
function logServerAddress (server) {
|
|
273
|
+
let address = server.address()
|
|
274
|
+
const isUnixSocket = typeof address === 'string'
|
|
275
|
+
/* istanbul ignore next */
|
|
276
|
+
if (!isUnixSocket) {
|
|
277
|
+
if (address.address.indexOf(':') === -1) {
|
|
278
|
+
address = address.address + ':' + address.port
|
|
279
|
+
} else {
|
|
280
|
+
address = '[' + address.address + ']:' + address.port
|
|
142
281
|
}
|
|
143
|
-
|
|
144
|
-
if (cb === undefined) return listenPromise(listenOptions)
|
|
145
|
-
|
|
146
|
-
this.ready(err => {
|
|
147
|
-
if (err != null) return cb(err)
|
|
148
|
-
|
|
149
|
-
if (this[kState].listening && this[kState].closing) {
|
|
150
|
-
return cb(new FST_ERR_REOPENED_CLOSE_SERVER(), null)
|
|
151
|
-
} else if (this[kState].listening) {
|
|
152
|
-
return cb(new FST_ERR_REOPENED_SERVER(), null)
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
server.once('error', wrap)
|
|
156
|
-
server.listen(listenOptions, wrap)
|
|
157
|
-
|
|
158
|
-
this[kState].listening = true
|
|
159
|
-
})
|
|
160
282
|
}
|
|
283
|
+
/* istanbul ignore next */
|
|
284
|
+
address = (isUnixSocket ? '' : ('http' + (this[kOptions].https ? 's' : '') + '://')) + address
|
|
285
|
+
|
|
286
|
+
this.log.info('Server listening at ' + address)
|
|
287
|
+
return address
|
|
161
288
|
}
|
|
162
289
|
|
|
163
290
|
function http2 () {
|
|
@@ -177,5 +304,3 @@ function sessionTimeout (timeout) {
|
|
|
177
304
|
function close () {
|
|
178
305
|
this.close()
|
|
179
306
|
}
|
|
180
|
-
|
|
181
|
-
module.exports = { createServer }
|
package/lib/symbols.js
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
const keys = {
|
|
4
4
|
kAvvioBoot: Symbol('fastify.avvioBoot'),
|
|
5
5
|
kChildren: Symbol('fastify.children'),
|
|
6
|
+
kServerBindings: Symbol('fastify.serverBindings'),
|
|
6
7
|
kBodyLimit: Symbol('fastify.bodyLimit'),
|
|
7
8
|
kRoutePrefix: Symbol('fastify.routePrefix'),
|
|
8
9
|
kLogLevel: Symbol('fastify.logLevel'),
|
|
9
10
|
kLogSerializers: Symbol('fastify.logSerializers'),
|
|
10
11
|
kHooks: Symbol('fastify.hooks'),
|
|
11
|
-
kHooksDeprecatedPreParsing: Symbol('fastify.hooks.DeprecatedPreParsing'),
|
|
12
12
|
kSchemaController: Symbol('fastify.schemaController'),
|
|
13
13
|
kSchemaHeaders: Symbol('headers-schema'),
|
|
14
14
|
kSchemaParams: Symbol('params-schema'),
|
|
@@ -31,9 +31,9 @@ const keys = {
|
|
|
31
31
|
kReplyIsError: Symbol('fastify.reply.isError'),
|
|
32
32
|
kReplyHeaders: Symbol('fastify.reply.headers'),
|
|
33
33
|
kReplyHasStatusCode: Symbol('fastify.reply.hasStatusCode'),
|
|
34
|
-
|
|
35
|
-
kReplySentOverwritten: Symbol('fastify.reply.sentOverwritten'),
|
|
34
|
+
kReplyHijacked: Symbol('fastify.reply.hijacked'),
|
|
36
35
|
kReplyStartTime: Symbol('fastify.reply.startTime'),
|
|
36
|
+
kReplyNextErrorHandler: Symbol('fastify.reply.nextErrorHandler'),
|
|
37
37
|
kReplyEndTime: Symbol('fastify.reply.endTime'),
|
|
38
38
|
kReplyErrorHandlerCalled: Symbol('fastify.reply.errorHandlerCalled'),
|
|
39
39
|
kReplyIsRunningOnErrorHook: Symbol('fastify.reply.isRunningOnErrorHook'),
|
|
@@ -45,6 +45,7 @@ const keys = {
|
|
|
45
45
|
// This symbol is only meant to be used for fastify tests and should not be used for any other purpose
|
|
46
46
|
kTestInternals: Symbol('fastify.testInternals'),
|
|
47
47
|
kErrorHandler: Symbol('fastify.errorHandler'),
|
|
48
|
+
kHasBeenDecorated: Symbol('fastify.hasBeenDecorated'),
|
|
48
49
|
kKeepAliveConnections: Symbol('fastify.keepAliveConnections')
|
|
49
50
|
}
|
|
50
51
|
|
package/lib/validation.js
CHANGED
|
@@ -68,7 +68,8 @@ function compileSchemasForValidation (context, compile) {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
function validateParam (validatorFunction, request, paramName) {
|
|
71
|
-
const
|
|
71
|
+
const isUndefined = request[paramName] === undefined
|
|
72
|
+
const ret = validatorFunction && validatorFunction(isUndefined ? null : request[paramName])
|
|
72
73
|
if (ret === false) return validatorFunction.errors
|
|
73
74
|
if (ret && ret.error) return ret.error
|
|
74
75
|
if (ret && ret.value) request[paramName] = ret.value
|
package/lib/warnings.js
CHANGED
|
@@ -4,21 +4,9 @@ const warning = require('process-warning')()
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Deprecation codes:
|
|
7
|
-
* - FSTDEP001
|
|
8
|
-
* - FSTDEP002
|
|
9
|
-
* - FSTDEP003
|
|
10
|
-
* - FSTDEP004
|
|
11
7
|
* - FSTDEP005
|
|
12
8
|
*/
|
|
13
9
|
|
|
14
|
-
warning.create('FastifyDeprecation', 'FSTDEP001', 'You are accessing the Node.js core request object via "request.req", Use "request.raw" instead.')
|
|
15
|
-
|
|
16
|
-
warning.create('FastifyDeprecation', 'FSTDEP002', 'You are accessing the Node.js core response object via "reply.res", Use "reply.raw" instead.')
|
|
17
|
-
|
|
18
|
-
warning.create('FastifyDeprecation', 'FSTDEP003', 'You are using the legacy Content Type Parser function signature. Use the one suggested in the documentation instead.')
|
|
19
|
-
|
|
20
|
-
warning.create('FastifyDeprecation', 'FSTDEP004', 'You are using the legacy preParsing hook signature. Use the one suggested in the documentation instead.')
|
|
21
|
-
|
|
22
10
|
warning.create('FastifyDeprecation', 'FSTDEP005', 'You are accessing the deprecated "request.connection" property. Use "request.socket" instead.')
|
|
23
11
|
|
|
24
12
|
warning.create('FastifyDeprecation', 'FSTDEP006', 'You are decorating Request/Reply with a reference type. This reference is shared amongst all requests. Use onRequest hook instead. Property: %s')
|
|
@@ -29,4 +17,8 @@ warning.create('FastifyDeprecation', 'FSTDEP008', 'You are using route constrain
|
|
|
29
17
|
|
|
30
18
|
warning.create('FastifyDeprecation', 'FSTDEP009', 'You are using a custom route versioning strategy via the server { versioning: "..." } option, use { constraints: { version: "..." } } option instead.')
|
|
31
19
|
|
|
20
|
+
warning.create('FastifyDeprecation', 'FSTDEP010', 'Modifying the "reply.sent" property is deprecated. Use the "reply.hijack()" method instead.')
|
|
21
|
+
|
|
22
|
+
warning.create('FastifyDeprecation', 'FSTDEP011', 'Variadic listen method is deprecated. Please use ".listen(optionsObject)" instead. The variadic signature will be removed in `fastify@5`.')
|
|
23
|
+
|
|
32
24
|
module.exports = warning
|
package/lib/wrapThenable.js
CHANGED
|
@@ -2,40 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
const {
|
|
4
4
|
kReplyIsError,
|
|
5
|
-
|
|
6
|
-
kReplySentOverwritten
|
|
5
|
+
kReplyHijacked
|
|
7
6
|
} = require('./symbols')
|
|
8
7
|
|
|
9
|
-
const { FST_ERR_PROMISE_NOT_FULFILLED } = require('./errors')
|
|
10
|
-
|
|
11
8
|
function wrapThenable (thenable, reply) {
|
|
12
9
|
thenable.then(function (payload) {
|
|
13
|
-
if (reply[
|
|
10
|
+
if (reply[kReplyHijacked] === true) {
|
|
14
11
|
return
|
|
15
12
|
}
|
|
16
13
|
|
|
17
14
|
// this is for async functions that
|
|
18
15
|
// are using reply.send directly
|
|
19
|
-
if (payload !== undefined ||
|
|
16
|
+
if (payload !== undefined || reply.sent === false) {
|
|
20
17
|
// we use a try-catch internally to avoid adding a catch to another
|
|
21
18
|
// promise, increase promise perf by 10%
|
|
22
19
|
try {
|
|
23
20
|
reply.send(payload)
|
|
24
21
|
} catch (err) {
|
|
25
|
-
reply[kReplySent] = false
|
|
26
22
|
reply[kReplyIsError] = true
|
|
27
23
|
reply.send(err)
|
|
28
24
|
}
|
|
29
|
-
} else if (reply[kReplySent] === false) {
|
|
30
|
-
reply.log.error({ err: new FST_ERR_PROMISE_NOT_FULFILLED() }, "Promise may not be fulfilled with 'undefined' when statusCode is not 204")
|
|
31
25
|
}
|
|
32
26
|
}, function (err) {
|
|
33
|
-
if (reply
|
|
27
|
+
if (reply.sent === true) {
|
|
34
28
|
reply.log.error({ err }, 'Promise errored, but reply.sent = true was set')
|
|
35
29
|
return
|
|
36
30
|
}
|
|
37
31
|
|
|
38
|
-
reply[kReplySent] = false
|
|
39
32
|
reply[kReplyIsError] = true
|
|
40
33
|
reply.send(err)
|
|
41
34
|
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fastify",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0-alpha.2",
|
|
4
4
|
"description": "Fast and low overhead web framework, for Node.js",
|
|
5
5
|
"main": "fastify.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
"bench": "branchcmp -r 2 -g -s \"npm run benchmark\"",
|
|
10
10
|
"benchmark": "npx concurrently -k -s first \"node ./examples/benchmark/simple.js\" \"npx autocannon -c 100 -d 30 -p 10 localhost:3000/\"",
|
|
11
11
|
"coverage": "npm run unit -- --cov --coverage-report=html",
|
|
12
|
+
"coverage:ci": "npm run unit -- --cov --coverage-report=html --no-browser --no-check-coverage -R terse",
|
|
13
|
+
"coverage:ci-check-coverage": "nyc check-coverage --branches 100 --functions 100 --lines 100 --statements 100",
|
|
12
14
|
"license-checker": "license-checker --production --onlyAllow=\"MIT;ISC;BSD-3-Clause;BSD-2-Clause\"",
|
|
13
15
|
"lint": "npm run lint:standard && npm run lint:typescript",
|
|
14
16
|
"lint:fix": "standard --fix",
|
|
@@ -18,10 +20,11 @@
|
|
|
18
20
|
"test": "npm run lint && npm run unit && npm run test:typescript",
|
|
19
21
|
"test:ci": "npm run unit -- -R terse --cov --coverage-report=lcovonly && npm run test:typescript",
|
|
20
22
|
"test:report": "npm run lint && npm run unit:report && npm run test:typescript",
|
|
21
|
-
"test:typescript": "tsd",
|
|
22
|
-
"
|
|
23
|
+
"test:typescript": "tsc test/types/import.ts && tsd",
|
|
24
|
+
"test:watch": "npm run unit -- -w --no-coverage-report -R terse",
|
|
25
|
+
"unit": "tap",
|
|
23
26
|
"unit:junit": "tap-mocha-reporter xunit < out.tap > test/junit-testresults.xml",
|
|
24
|
-
"unit:report": "tap
|
|
27
|
+
"unit:report": "tap --cov --coverage-report=html --coverage-report=cobertura | tee out.tap"
|
|
25
28
|
},
|
|
26
29
|
"repository": {
|
|
27
30
|
"type": "git",
|
|
@@ -121,24 +124,19 @@
|
|
|
121
124
|
},
|
|
122
125
|
"homepage": "https://www.fastify.io/",
|
|
123
126
|
"devDependencies": {
|
|
124
|
-
"@fastify/ajv-compiler-8": "npm:@fastify/ajv-compiler@^2.0.0",
|
|
125
127
|
"@fastify/pre-commit": "^2.0.1",
|
|
126
|
-
"@
|
|
128
|
+
"@sinclair/typebox": "^0.23.1",
|
|
127
129
|
"@sinonjs/fake-timers": "^9.1.0",
|
|
128
|
-
"@types/node": "^
|
|
129
|
-
"@
|
|
130
|
-
"@typescript-eslint/
|
|
131
|
-
"
|
|
132
|
-
"
|
|
133
|
-
"ajv": "^6.0.0",
|
|
134
|
-
"ajv-errors": "^1.0.1",
|
|
130
|
+
"@types/node": "^17.0.18",
|
|
131
|
+
"@typescript-eslint/eslint-plugin": "^5.7.0",
|
|
132
|
+
"@typescript-eslint/parser": "^5.7.0",
|
|
133
|
+
"ajv": "^8.10.0",
|
|
134
|
+
"ajv-errors": "^3.0.0",
|
|
135
135
|
"ajv-formats": "^2.1.1",
|
|
136
|
-
"ajv-i18n": "^
|
|
137
|
-
"ajv-merge-patch": "^
|
|
138
|
-
"
|
|
139
|
-
"branch-comparer": "^1.0.2",
|
|
136
|
+
"ajv-i18n": "^4.2.0",
|
|
137
|
+
"ajv-merge-patch": "^5.0.1",
|
|
138
|
+
"branch-comparer": "^1.1.0",
|
|
140
139
|
"cors": "^2.8.5",
|
|
141
|
-
"coveralls": "^3.1.0",
|
|
142
140
|
"dns-prefetch-control": "^0.3.0",
|
|
143
141
|
"eslint": "^8.0.1",
|
|
144
142
|
"eslint-config-standard": "^17.0.0-1",
|
|
@@ -147,46 +145,45 @@
|
|
|
147
145
|
"eslint-plugin-n": "^14.0.0",
|
|
148
146
|
"eslint-plugin-promise": "^6.0.0",
|
|
149
147
|
"fast-json-body": "^1.1.0",
|
|
148
|
+
"fast-json-stringify": "^3.0.0",
|
|
150
149
|
"fastify-plugin": "^3.0.0",
|
|
151
|
-
"fluent-json-schema": "^3.0.
|
|
150
|
+
"fluent-json-schema": "^3.0.1",
|
|
152
151
|
"form-data": "^4.0.0",
|
|
153
152
|
"frameguard": "^4.0.0",
|
|
154
153
|
"h2url": "^0.2.0",
|
|
155
154
|
"helmet": "^5.0.1",
|
|
156
155
|
"hide-powered-by": "^1.1.0",
|
|
157
|
-
"hsts": "^2.2.0",
|
|
158
156
|
"http-errors": "^2.0.0",
|
|
159
|
-
"
|
|
157
|
+
"joi": "^17.5.0",
|
|
158
|
+
"json-schema-to-ts": "^1.6.4",
|
|
159
|
+
"JSONStream": "^1.3.5",
|
|
160
160
|
"license-checker": "^25.0.1",
|
|
161
|
-
"pem": "^1.14.4",
|
|
162
161
|
"proxyquire": "^2.1.3",
|
|
163
162
|
"pump": "^3.0.0",
|
|
164
|
-
"
|
|
163
|
+
"self-cert": "^2.0.0",
|
|
164
|
+
"send": "^0.17.2",
|
|
165
165
|
"serve-static": "^1.14.1",
|
|
166
166
|
"simple-get": "^4.0.0",
|
|
167
167
|
"snazzy": "^9.0.0",
|
|
168
168
|
"split2": "^4.1.0",
|
|
169
169
|
"standard": "^17.0.0-2",
|
|
170
|
-
"tap": "^
|
|
171
|
-
"
|
|
172
|
-
"
|
|
173
|
-
"
|
|
174
|
-
"typescript": "^4.0.2",
|
|
175
|
-
"undici": "^3.3.6",
|
|
170
|
+
"tap": "^16.0.0",
|
|
171
|
+
"tsd": "^0.19.1",
|
|
172
|
+
"typescript": "^4.5.4",
|
|
173
|
+
"undici": "^4.11.3",
|
|
176
174
|
"x-xss-protection": "^2.0.0",
|
|
177
|
-
"yup": "^0.32.
|
|
175
|
+
"yup": "^0.32.11"
|
|
178
176
|
},
|
|
179
177
|
"dependencies": {
|
|
180
|
-
"@fastify/ajv-compiler": "^1.0
|
|
181
|
-
"
|
|
182
|
-
"
|
|
183
|
-
"
|
|
184
|
-
"fastify-error": "^0.
|
|
178
|
+
"@fastify/ajv-compiler": "^3.1.0",
|
|
179
|
+
"@fastify/fast-json-stringify-compiler": "^1.0.0",
|
|
180
|
+
"abstract-logging": "^2.0.1",
|
|
181
|
+
"avvio": "^8.1.0",
|
|
182
|
+
"fastify-error": "^1.0.0",
|
|
183
|
+
"find-my-way": "^5.1.0",
|
|
184
|
+
"light-my-request": "^4.7.0",
|
|
185
|
+
"pino": "^7.5.1",
|
|
185
186
|
"process-warning": "^1.0.0",
|
|
186
|
-
"find-my-way": "^4.5.0",
|
|
187
|
-
"flatstr": "^1.0.12",
|
|
188
|
-
"light-my-request": "^4.2.0",
|
|
189
|
-
"pino": "^6.13.0",
|
|
190
187
|
"proxy-addr": "^2.0.7",
|
|
191
188
|
"rfdc": "^1.1.4",
|
|
192
189
|
"secure-json-parse": "^2.0.0",
|
|
@@ -196,6 +193,7 @@
|
|
|
196
193
|
"standard": {
|
|
197
194
|
"ignore": [
|
|
198
195
|
"lib/configValidator.js",
|
|
196
|
+
"lib/error-serializer.js",
|
|
199
197
|
"fastify.d.ts",
|
|
200
198
|
"types/*",
|
|
201
199
|
"test/types/*",
|