fastify 3.26.0 → 4.0.0-alpha.1

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 (129) hide show
  1. package/README.md +5 -4
  2. package/build/build-error-serializer.js +27 -0
  3. package/build/build-validation.js +49 -35
  4. package/docs/Guides/Ecosystem.md +2 -1
  5. package/docs/Guides/Prototype-Poisoning.md +3 -3
  6. package/docs/Migration-Guide-V4.md +12 -0
  7. package/docs/Reference/ContentTypeParser.md +8 -1
  8. package/docs/Reference/Errors.md +51 -6
  9. package/docs/Reference/Hooks.md +4 -7
  10. package/docs/Reference/LTS.md +5 -4
  11. package/docs/Reference/Reply.md +23 -22
  12. package/docs/Reference/Request.md +1 -3
  13. package/docs/Reference/Routes.md +17 -10
  14. package/docs/Reference/Server.md +98 -63
  15. package/docs/Reference/TypeScript.md +11 -13
  16. package/docs/Reference/Validation-and-Serialization.md +32 -54
  17. package/docs/Type-Providers.md +257 -0
  18. package/examples/hooks.js +1 -1
  19. package/examples/simple-stream.js +18 -0
  20. package/fastify.d.ts +36 -22
  21. package/fastify.js +72 -53
  22. package/lib/configValidator.js +902 -1023
  23. package/lib/contentTypeParser.js +6 -16
  24. package/lib/context.js +36 -10
  25. package/lib/decorate.js +5 -3
  26. package/lib/error-handler.js +158 -0
  27. package/lib/error-serializer.js +257 -0
  28. package/lib/errors.js +49 -10
  29. package/lib/fourOhFour.js +31 -20
  30. package/lib/handleRequest.js +10 -13
  31. package/lib/hooks.js +14 -9
  32. package/lib/noop-set.js +10 -0
  33. package/lib/pluginOverride.js +0 -3
  34. package/lib/pluginUtils.js +3 -2
  35. package/lib/reply.js +44 -163
  36. package/lib/request.js +13 -10
  37. package/lib/route.js +158 -139
  38. package/lib/schema-controller.js +3 -3
  39. package/lib/schemas.js +27 -1
  40. package/lib/server.js +219 -116
  41. package/lib/symbols.js +6 -4
  42. package/lib/validation.js +2 -1
  43. package/lib/warnings.js +2 -12
  44. package/lib/wrapThenable.js +4 -11
  45. package/package.json +40 -45
  46. package/test/404s.test.js +265 -108
  47. package/test/500s.test.js +2 -2
  48. package/test/async-await.test.js +15 -71
  49. package/test/close.test.js +39 -1
  50. package/test/content-parser.test.js +32 -0
  51. package/test/context-config.test.js +56 -4
  52. package/test/custom-http-server.test.js +14 -7
  53. package/test/custom-parser-async.test.js +0 -65
  54. package/test/custom-parser.test.js +54 -121
  55. package/test/decorator.test.js +1 -3
  56. package/test/delete.test.js +5 -5
  57. package/test/encapsulated-error-handler.test.js +50 -0
  58. package/test/esm/index.test.js +0 -14
  59. package/test/fastify-instance.test.js +4 -4
  60. package/test/fluent-schema.test.js +4 -4
  61. package/test/get.test.js +3 -3
  62. package/test/helper.js +18 -3
  63. package/test/hooks-async.test.js +14 -47
  64. package/test/hooks.on-ready.test.js +9 -4
  65. package/test/hooks.test.js +58 -99
  66. package/test/http2/closing.test.js +5 -11
  67. package/test/http2/unknown-http-method.test.js +3 -9
  68. package/test/https/custom-https-server.test.js +12 -6
  69. package/test/inject.test.js +1 -1
  70. package/test/input-validation.js +2 -2
  71. package/test/internals/all.test.js +2 -2
  72. package/test/internals/contentTypeParser.test.js +4 -4
  73. package/test/internals/handleRequest.test.js +9 -46
  74. package/test/internals/initialConfig.test.js +33 -12
  75. package/test/internals/logger.test.js +1 -1
  76. package/test/internals/reply.test.js +245 -3
  77. package/test/internals/request.test.js +13 -7
  78. package/test/internals/server.test.js +88 -0
  79. package/test/listen.test.js +84 -1
  80. package/test/logger.test.js +98 -58
  81. package/test/maxRequestsPerSocket.test.js +8 -6
  82. package/test/middleware.test.js +2 -25
  83. package/test/noop-set.test.js +19 -0
  84. package/test/nullable-validation.test.js +51 -14
  85. package/test/plugin.test.js +31 -5
  86. package/test/pretty-print.test.js +22 -10
  87. package/test/reply-error.test.js +123 -12
  88. package/test/request-error.test.js +2 -5
  89. package/test/route-hooks.test.js +17 -17
  90. package/test/route-prefix.test.js +2 -1
  91. package/test/route.test.js +216 -20
  92. package/test/router-options.test.js +1 -1
  93. package/test/schema-examples.test.js +11 -5
  94. package/test/schema-feature.test.js +24 -19
  95. package/test/schema-serialization.test.js +50 -9
  96. package/test/schema-special-usage.test.js +14 -81
  97. package/test/schema-validation.test.js +9 -9
  98. package/test/skip-reply-send.test.js +8 -8
  99. package/test/stream.test.js +23 -12
  100. package/test/throw.test.js +8 -5
  101. package/test/trust-proxy.test.js +1 -1
  102. package/test/type-provider.test.js +20 -0
  103. package/test/types/fastify.test-d.ts +12 -18
  104. package/test/types/hooks.test-d.ts +7 -3
  105. package/test/types/import.js +2 -0
  106. package/test/types/import.ts +1 -0
  107. package/test/types/instance.test-d.ts +61 -15
  108. package/test/types/logger.test-d.ts +44 -15
  109. package/test/types/route.test-d.ts +8 -2
  110. package/test/types/schema.test-d.ts +2 -39
  111. package/test/types/type-provider.test-d.ts +417 -0
  112. package/test/validation-error-handling.test.js +9 -9
  113. package/test/versioned-routes.test.js +29 -17
  114. package/test/wrapThenable.test.js +7 -6
  115. package/types/.eslintrc.json +1 -1
  116. package/types/content-type-parser.d.ts +17 -8
  117. package/types/hooks.d.ts +107 -60
  118. package/types/instance.d.ts +137 -105
  119. package/types/logger.d.ts +18 -104
  120. package/types/plugin.d.ts +10 -4
  121. package/types/register.d.ts +1 -1
  122. package/types/reply.d.ts +16 -11
  123. package/types/request.d.ts +10 -5
  124. package/types/route.d.ts +42 -31
  125. package/types/schema.d.ts +15 -1
  126. package/types/type-provider.d.ts +99 -0
  127. package/types/utils.d.ts +1 -1
  128. package/lib/schema-compilers.js +0 -12
  129. package/test/emit-warning.test.js +0 -166
package/lib/server.js CHANGED
@@ -1,16 +1,187 @@
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 { kState, kOptions } = require('./symbols')
7
+ const { kState, kOptions, kServerBindings } = require('./symbols')
8
8
  const { FST_ERR_HTTP2_INVALID_VERSION, FST_ERR_REOPENED_CLOSE_SERVER, FST_ERR_REOPENED_SERVER } = require('./errors')
9
9
 
10
+ module.exports = createServer
11
+
10
12
  function createServer (options, httpHandler) {
11
- assert(options, 'Missing options')
12
- assert(httpHandler, 'Missing http handler')
13
+ const server = getServerInstance(options, httpHandler)
14
+
15
+ return { server, listen }
16
+
17
+ // `this` is the Fastify object
18
+ function listen () {
19
+ const listenOptions = normalizeListenArgs(Array.from(arguments))
20
+ const { cb, host } = listenOptions
21
+
22
+ if (host === 'localhost') {
23
+ listenOptions.cb = (err, address) => {
24
+ if (err) {
25
+ // the server did not start
26
+ cb(err, address)
27
+ return
28
+ }
29
+
30
+ multipleBindings.call(this, server, httpHandler, options, listenOptions, () => {
31
+ this[kState].listening = true
32
+ cb(null, address)
33
+ })
34
+ }
35
+ }
36
+
37
+ // https://github.com/nodejs/node/issues/9390
38
+ // If listening to 'localhost', listen to both 127.0.0.1 or ::1 if they are available.
39
+ // If listening to 127.0.0.1, only listen to 127.0.0.1.
40
+ // If listening to ::1, only listen to ::1.
41
+
42
+ if (cb === undefined) {
43
+ const listening = listenPromise.call(this, server, listenOptions)
44
+ if (host === 'localhost') {
45
+ return listening.then(address => {
46
+ return new Promise((resolve, reject) => {
47
+ multipleBindings.call(this, server, httpHandler, options, listenOptions, () => {
48
+ this[kState].listening = true
49
+ resolve(address)
50
+ })
51
+ })
52
+ })
53
+ }
54
+ return listening
55
+ }
56
+
57
+ this.ready(listenCallback.call(this, server, listenOptions))
58
+ }
59
+ }
60
+
61
+ function multipleBindings (mainServer, httpHandler, serverOpts, listenOptions, onListen) {
62
+ // the main server is started, we need to start the secondary servers
63
+ this[kState].listening = false
64
+
65
+ // let's check if we need to bind additional addresses
66
+ dns.lookup(listenOptions.host, { all: true }, (dnsErr, addresses) => {
67
+ if (dnsErr) {
68
+ // not blocking the main server listening
69
+ // this.log.warn('dns.lookup error:', dnsErr)
70
+ onListen()
71
+ return
72
+ }
13
73
 
74
+ let binding = 0
75
+ let binded = 0
76
+ const primaryAddress = mainServer.address()
77
+ for (const adr of addresses) {
78
+ if (adr.address !== primaryAddress.address) {
79
+ binding++
80
+ const secondaryOpts = Object.assign({}, listenOptions, {
81
+ host: adr.address,
82
+ port: primaryAddress.port,
83
+ cb: (_ignoreErr) => {
84
+ binded++
85
+
86
+ if (!_ignoreErr) {
87
+ this[kServerBindings].push(secondaryServer)
88
+ }
89
+
90
+ if (binded === binding) {
91
+ // regardless of the error, we are done
92
+ onListen()
93
+ }
94
+ }
95
+ })
96
+
97
+ const secondaryServer = getServerInstance(serverOpts, httpHandler)
98
+ const closeSecondary = () => { secondaryServer.close(() => {}) }
99
+ mainServer.on('unref', closeSecondary)
100
+ mainServer.on('close', closeSecondary)
101
+ mainServer.on('error', closeSecondary)
102
+ listenCallback.call(this, secondaryServer, secondaryOpts)()
103
+ }
104
+ }
105
+
106
+ // no extra bindings are necessary
107
+ if (binding === 0) {
108
+ onListen()
109
+ return
110
+ }
111
+
112
+ // in test files we are using unref so we need to propagate the unref event
113
+ // to the secondary servers. It is valid only when the user is
114
+ // listening on localhost
115
+ const originUnref = mainServer.unref
116
+ /* istanbul ignore next */
117
+ mainServer.unref = function () {
118
+ originUnref.call(mainServer)
119
+ mainServer.emit('unref')
120
+ }
121
+ })
122
+ }
123
+
124
+ function listenCallback (server, listenOptions) {
125
+ const wrap = (err) => {
126
+ server.removeListener('error', wrap)
127
+ if (!err) {
128
+ const address = logServerAddress.call(this, server)
129
+ listenOptions.cb(null, address)
130
+ } else {
131
+ this[kState].listening = false
132
+ listenOptions.cb(err, null)
133
+ }
134
+ }
135
+
136
+ return (err) => {
137
+ if (err != null) return listenOptions.cb(err)
138
+
139
+ if (this[kState].listening && this[kState].closing) {
140
+ return listenOptions.cb(new FST_ERR_REOPENED_CLOSE_SERVER(), null)
141
+ } else if (this[kState].listening) {
142
+ return listenOptions.cb(new FST_ERR_REOPENED_SERVER(), null)
143
+ }
144
+
145
+ server.once('error', wrap)
146
+ server.listen(listenOptions, wrap)
147
+
148
+ this[kState].listening = true
149
+ }
150
+ }
151
+
152
+ function listenPromise (server, listenOptions) {
153
+ if (this[kState].listening && this[kState].closing) {
154
+ return Promise.reject(new FST_ERR_REOPENED_CLOSE_SERVER())
155
+ } else if (this[kState].listening) {
156
+ return Promise.reject(new FST_ERR_REOPENED_SERVER())
157
+ }
158
+
159
+ return this.ready().then(() => {
160
+ let errEventHandler
161
+ const errEvent = new Promise((resolve, reject) => {
162
+ errEventHandler = (err) => {
163
+ this[kState].listening = false
164
+ reject(err)
165
+ }
166
+ server.once('error', errEventHandler)
167
+ })
168
+ const listen = new Promise((resolve, reject) => {
169
+ server.listen(listenOptions, () => {
170
+ server.removeListener('error', errEventHandler)
171
+ resolve(logServerAddress.call(this, server))
172
+ })
173
+ // we set it afterwards because listen can throw
174
+ this[kState].listening = true
175
+ })
176
+
177
+ return Promise.race([
178
+ errEvent, // e.g invalid port range error is always emitted before the server listening
179
+ listen
180
+ ])
181
+ })
182
+ }
183
+
184
+ function getServerInstance (options, httpHandler) {
14
185
  let server = null
15
186
  if (options.serverFactory) {
16
187
  server = options.serverFactory(httpHandler, options)
@@ -41,123 +212,57 @@ function createServer (options, httpHandler) {
41
212
  if (!options.serverFactory) {
42
213
  server.setTimeout(options.connectionTimeout)
43
214
  }
215
+ return server
216
+ }
44
217
 
45
- return { server, listen }
46
-
47
- // `this` is the Fastify object
48
- function listen () {
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: 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
- }
218
+ function normalizeListenArgs (args) {
219
+ if (args.length === 0) {
220
+ return { port: 0, host: 'localhost' }
221
+ }
94
222
 
95
- const listenPromise = (listenOptions) => {
96
- if (this[kState].listening && this[kState].closing) {
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
- }
223
+ const cb = typeof args[args.length - 1] === 'function' ? args.pop() : undefined
224
+ const options = { cb }
101
225
 
102
- return this.ready().then(() => {
103
- let errEventHandler
104
- const errEvent = new Promise((resolve, reject) => {
105
- errEventHandler = (err) => {
106
- this[kState].listening = false
107
- reject(err)
108
- }
109
- server.once('error', errEventHandler)
110
- })
111
- const listen = new Promise((resolve, reject) => {
112
- server.listen(listenOptions, () => {
113
- server.removeListener('error', errEventHandler)
114
- resolve(logServerAddress())
115
- })
116
- // we set it afterwards because listen can throw
117
- this[kState].listening = true
118
- })
226
+ const firstArg = args[0]
227
+ const argsLength = args.length
228
+ const lastArg = args[argsLength - 1]
229
+ /* Deal with listen (options) || (handle[, backlog]) */
230
+ if (typeof firstArg === 'object' && firstArg !== null) {
231
+ options.backlog = argsLength > 1 ? lastArg : undefined
232
+ Object.assign(options, firstArg)
233
+ } else if (typeof firstArg === 'string' && isNaN(firstArg)) {
234
+ /* Deal with listen (pipe[, backlog]) */
235
+ options.path = firstArg
236
+ options.backlog = argsLength > 1 ? lastArg : undefined
237
+ } else {
238
+ /* Deal with listen ([port[, host[, backlog]]]) */
239
+ options.port = argsLength >= 1 && firstArg ? firstArg : 0
240
+ // This will listen to what localhost is.
241
+ // It can be 127.0.0.1 or ::1, depending on the operating system.
242
+ // Fixes https://github.com/fastify/fastify/issues/1022.
243
+ options.host = argsLength >= 2 && args[1] ? args[1] : 'localhost'
244
+ options.backlog = argsLength >= 3 ? args[2] : undefined
245
+ }
119
246
 
120
- return Promise.race([
121
- errEvent, // e.g invalid port range error is always emitted before the server listening
122
- listen
123
- ])
124
- })
125
- }
247
+ return options
248
+ }
126
249
 
127
- const logServerAddress = () => {
128
- let address = server.address()
129
- const isUnixSocket = typeof address === 'string'
130
- /* istanbul ignore next */
131
- if (!isUnixSocket) {
132
- if (address.address.indexOf(':') === -1) {
133
- address = address.address + ':' + address.port
134
- } else {
135
- address = '[' + address.address + ']:' + address.port
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
250
+ function logServerAddress (server) {
251
+ let address = server.address()
252
+ const isUnixSocket = typeof address === 'string'
253
+ /* istanbul ignore next */
254
+ if (!isUnixSocket) {
255
+ if (address.address.indexOf(':') === -1) {
256
+ address = address.address + ':' + address.port
257
+ } else {
258
+ address = '[' + address.address + ']:' + address.port
142
259
  }
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
260
  }
261
+ /* istanbul ignore next */
262
+ address = (isUnixSocket ? '' : ('http' + (this[kOptions].https ? 's' : '') + '://')) + address
263
+
264
+ this.log.info('Server listening at ' + address)
265
+ return address
161
266
  }
162
267
 
163
268
  function http2 () {
@@ -177,5 +282,3 @@ function sessionTimeout (timeout) {
177
282
  function close () {
178
283
  this.close()
179
284
  }
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
- kReplySent: Symbol('fastify.reply.sent'),
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'),
@@ -44,7 +44,9 @@ const keys = {
44
44
  kPluginNameChain: Symbol('fastify.pluginNameChain'),
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
- kErrorHandler: Symbol('fastify.errorHandler')
47
+ kErrorHandler: Symbol('fastify.errorHandler'),
48
+ kHasBeenDecorated: Symbol('fastify.hasBeenDecorated'),
49
+ kKeepAliveConnections: Symbol('fastify.keepAliveConnections')
48
50
  }
49
51
 
50
52
  module.exports = keys
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 ret = validatorFunction && validatorFunction(request[paramName])
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,6 @@ 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
+
32
22
  module.exports = warning
@@ -2,40 +2,33 @@
2
2
 
3
3
  const {
4
4
  kReplyIsError,
5
- kReplySent,
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[kReplySentOverwritten] === true) {
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 || (reply.raw.statusCode === 204 && reply[kReplySent] === false)) {
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[kReplySentOverwritten] === true || reply.sent === true) {
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.26.0",
3
+ "version": "4.0.0-alpha.1",
4
4
  "description": "Fast and low overhead web framework, for Node.js",
5
5
  "main": "fastify.js",
6
6
  "type": "commonjs",
@@ -12,13 +12,13 @@
12
12
  "license-checker": "license-checker --production --onlyAllow=\"MIT;ISC;BSD-3-Clause;BSD-2-Clause\"",
13
13
  "lint": "npm run lint:standard && npm run lint:typescript",
14
14
  "lint:fix": "standard --fix",
15
- "lint:standard": "standard --verbose | snazzy",
15
+ "lint:standard": "standard | snazzy",
16
16
  "lint:typescript": "eslint -c types/.eslintrc.json types/**/*.d.ts test/types/**/*.test-d.ts",
17
17
  "prepublishOnly": "tap --no-check-coverage test/internals/version.test.js",
18
18
  "test": "npm run lint && npm run unit && npm run test:typescript",
19
- "test:ci": "npm run unit -- --cov --coverage-report=lcovonly && npm run test:typescript",
19
+ "test:ci": "npm run unit -- -R terse --cov --coverage-report=lcovonly && npm run test:typescript",
20
20
  "test:report": "npm run lint && npm run unit:report && npm run test:typescript",
21
- "test:typescript": "tsd",
21
+ "test:typescript": "tsc test/types/import.ts && tsd",
22
22
  "unit": "tap -J test/*.test.js test/*/*.test.js",
23
23
  "unit:junit": "tap-mocha-reporter xunit < out.tap > test/junit-testresults.xml",
24
24
  "unit:report": "tap -J test/*.test.js test/*/*.test.js --cov --coverage-report=html --coverage-report=cobertura | tee out.tap"
@@ -121,82 +121,77 @@
121
121
  },
122
122
  "homepage": "https://www.fastify.io/",
123
123
  "devDependencies": {
124
+ "@fastify/ajv-compiler-6": "npm:@fastify/ajv-compiler@^1.0.0",
124
125
  "@fastify/ajv-compiler-8": "npm:@fastify/ajv-compiler@^2.0.0",
125
126
  "@fastify/pre-commit": "^2.0.1",
126
- "@hapi/joi": "^17.1.1",
127
- "@sinonjs/fake-timers": "^8.1.0",
127
+ "@sinonjs/fake-timers": "^9.1.0",
128
128
  "@types/node": "^16.0.0",
129
- "@types/pino": "^6.0.1",
130
- "@typescript-eslint/eslint-plugin": "^4.5.0",
131
- "@typescript-eslint/parser": "^4.5.0",
132
- "ajv": "^6.0.0",
133
- "ajv-errors": "^1.0.1",
129
+ "@sinclair/typebox": "^0.23.1",
130
+ "@typescript-eslint/eslint-plugin": "^5.7.0",
131
+ "@typescript-eslint/parser": "^5.7.0",
132
+ "ajv-errors": "^3.0.0",
134
133
  "ajv-formats": "^2.1.1",
135
- "ajv-i18n": "^3.5.0",
136
- "ajv-merge-patch": "^4.1.0",
137
- "ajv-pack": "^0.3.1",
138
- "branch-comparer": "^1.0.2",
134
+ "ajv-i18n": "^4.2.0",
135
+ "ajv-merge-patch": "^5.0.1",
136
+ "branch-comparer": "^1.1.0",
139
137
  "cors": "^2.8.5",
140
- "coveralls": "^3.1.0",
138
+ "coveralls": "^3.1.1",
141
139
  "dns-prefetch-control": "^0.3.0",
142
- "eslint": "^7.11.0",
143
- "eslint-config-standard": "^16.0.1",
140
+ "eslint": "^8.0.1",
141
+ "eslint-config-standard": "^17.0.0-1",
144
142
  "eslint-import-resolver-node": "^0.3.2",
145
- "eslint-plugin-import": "^2.20.2",
146
- "eslint-plugin-node": "^11.1.0",
147
- "eslint-plugin-promise": "^5.1.0",
148
- "eslint-plugin-standard": "^5.0.0",
143
+ "eslint-plugin-import": "^2.25.4",
144
+ "eslint-plugin-n": "^14.0.0",
145
+ "eslint-plugin-promise": "^6.0.0",
149
146
  "fast-json-body": "^1.1.0",
147
+ "fast-json-stringify": "^3.0.0",
150
148
  "fastify-plugin": "^3.0.0",
151
- "fluent-json-schema": "^3.0.0",
149
+ "fluent-json-schema": "^3.0.1",
152
150
  "form-data": "^4.0.0",
153
151
  "frameguard": "^4.0.0",
154
152
  "h2url": "^0.2.0",
155
153
  "helmet": "^5.0.1",
156
154
  "hide-powered-by": "^1.1.0",
157
- "hsts": "^2.2.0",
158
- "http-errors": "^2.0.0",
159
- "ienoopen": "^1.1.0",
155
+ "joi": "^17.5.0",
156
+ "json-schema-to-ts": "^1.6.4",
160
157
  "JSONStream": "^1.3.5",
161
158
  "license-checker": "^25.0.1",
162
159
  "pem": "^1.14.4",
163
160
  "proxyquire": "^2.1.3",
164
161
  "pump": "^3.0.0",
165
- "send": "^0.17.1",
162
+ "send": "^0.17.2",
166
163
  "serve-static": "^1.14.1",
167
164
  "simple-get": "^4.0.0",
168
165
  "snazzy": "^9.0.0",
169
166
  "split2": "^4.1.0",
170
- "standard": "^16.0.1",
171
- "tap": "^15.1.1",
172
- "tap-mocha-reporter": "^5.0.1",
173
- "then-sleep": "^1.0.1",
174
- "tsd": "^0.19.0",
175
- "typescript": "^4.0.2",
176
- "undici": "^3.3.5",
167
+ "standard": "^17.0.0-2",
168
+ "tap": "^15.1.6",
169
+ "tsd": "^0.19.1",
170
+ "typescript": "^4.5.4",
171
+ "undici": "^4.11.3",
177
172
  "x-xss-protection": "^2.0.0",
178
- "yup": "^0.32.0"
173
+ "yup": "^0.32.11"
179
174
  },
180
175
  "dependencies": {
181
- "@fastify/ajv-compiler": "^1.0.0",
182
- "abstract-logging": "^2.0.0",
183
- "avvio": "^7.1.2",
184
- "fast-json-stringify": "^2.5.2",
185
- "fastify-error": "^0.3.0",
176
+ "@fastify/ajv-compiler": "^3.1.0",
177
+ "@fastify/fast-json-stringify-compiler": "^1.0.0",
178
+ "abstract-logging": "^2.0.1",
179
+ "avvio": "^8.1.0",
180
+ "fastify-error": "^0.3.1",
181
+ "find-my-way": "^5.1.0",
182
+ "light-my-request": "^4.7.0",
183
+ "pino": "^7.5.1",
186
184
  "process-warning": "^1.0.0",
187
- "find-my-way": "^4.5.0",
188
- "flatstr": "^1.0.12",
189
- "light-my-request": "^4.2.0",
190
- "pino": "^6.13.0",
191
185
  "proxy-addr": "^2.0.7",
192
186
  "rfdc": "^1.1.4",
193
187
  "secure-json-parse": "^2.0.0",
194
188
  "semver": "^7.3.2",
195
- "tiny-lru": "^7.0.0"
189
+ "tiny-lru": "^8.0.1"
196
190
  },
197
191
  "standard": {
198
192
  "ignore": [
199
193
  "lib/configValidator.js",
194
+ "lib/error-serializer.js",
200
195
  "fastify.d.ts",
201
196
  "types/*",
202
197
  "test/types/*",