fastify 3.4.1 → 3.7.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 (54) hide show
  1. package/docs/ContentTypeParser.md +3 -0
  2. package/docs/Decorators.md +2 -0
  3. package/docs/Ecosystem.md +2 -1
  4. package/docs/Lifecycle.md +2 -2
  5. package/docs/Logging.md +1 -1
  6. package/docs/Reply.md +18 -0
  7. package/docs/Request.md +5 -1
  8. package/docs/Routes.md +2 -2
  9. package/docs/Server.md +55 -4
  10. package/docs/TypeScript.md +2 -1
  11. package/docs/Validation-and-Serialization.md +11 -5
  12. package/examples/simple.mjs +27 -0
  13. package/fastify.js +55 -7
  14. package/lib/contentTypeParser.js +4 -0
  15. package/lib/context.js +1 -16
  16. package/lib/errors.js +10 -2
  17. package/lib/fourOhFour.js +4 -3
  18. package/lib/logger.js +1 -1
  19. package/lib/pluginUtils.js +15 -0
  20. package/lib/reply.js +3 -3
  21. package/lib/request.js +26 -1
  22. package/lib/route.js +7 -3
  23. package/lib/symbols.js +2 -1
  24. package/lib/validation.js +1 -0
  25. package/lib/warnings.js +3 -0
  26. package/lib/wrapThenable.js +2 -2
  27. package/package.json +5 -5
  28. package/test/custom-parser.test.js +30 -0
  29. package/test/emit-warning.test.js +31 -0
  30. package/test/esm/index.test.js +15 -2
  31. package/test/esm/named-exports.mjs +13 -0
  32. package/test/fastify-instance.test.js +33 -1
  33. package/test/http2/secure.test.js +11 -0
  34. package/test/https/https.test.js +26 -0
  35. package/test/internals/request.test.js +8 -5
  36. package/test/internals/version.test.js +43 -0
  37. package/test/listen.test.js +16 -0
  38. package/test/logger.test.js +1 -1
  39. package/test/plugin.test.js +108 -0
  40. package/test/request-error.test.js +81 -0
  41. package/test/route.test.js +27 -0
  42. package/test/trust-proxy.test.js +42 -5
  43. package/test/types/decorate-request-reply.test-d.ts +18 -0
  44. package/test/types/instance.test-d.ts +27 -9
  45. package/test/types/logger.test-d.ts +63 -1
  46. package/test/types/register.test-d.ts +16 -0
  47. package/test/types/request.test-d.ts +1 -1
  48. package/test/types/schema.test-d.ts +5 -0
  49. package/test/validation-error-handling.test.js +66 -0
  50. package/types/instance.d.ts +7 -13
  51. package/types/logger.d.ts +90 -10
  52. package/types/register.d.ts +1 -0
  53. package/types/request.d.ts +20 -11
  54. package/types/schema.d.ts +2 -2
package/lib/request.js CHANGED
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const proxyAddr = require('proxy-addr')
4
+ const semver = require('semver')
4
5
  const warning = require('./warnings')
5
6
 
6
7
  function Request (id, params, req, query, log, context) {
@@ -78,6 +79,17 @@ function buildRequestWithTrustProxy (R, trustProxy) {
78
79
  }
79
80
  return this.headers.host || this.headers[':authority']
80
81
  }
82
+ },
83
+ protocol: {
84
+ get () {
85
+ if (this.headers['x-forwarded-proto']) {
86
+ const proto = this.headers['x-forwarded-proto']
87
+ // we use the last one if the header is set more than once
88
+ const lastIndex = proto.lastIndexOf(',')
89
+ return lastIndex === -1 ? proto.trim() : proto.slice(lastIndex + 1).trim()
90
+ }
91
+ return this.socket.encrypted ? 'https' : 'http'
92
+ }
81
93
  }
82
94
  })
83
95
 
@@ -118,12 +130,20 @@ Object.defineProperties(Request.prototype, {
118
130
  },
119
131
  connection: {
120
132
  get () {
133
+ if (semver.gte(process.versions.node, '13.0.0')) {
134
+ warning.emit('FSTDEP005')
135
+ }
121
136
  return this.raw.connection
122
137
  }
123
138
  },
139
+ socket: {
140
+ get () {
141
+ return this.raw.socket
142
+ }
143
+ },
124
144
  ip: {
125
145
  get () {
126
- return this.connection.remoteAddress
146
+ return this.socket.remoteAddress
127
147
  }
128
148
  },
129
149
  hostname: {
@@ -131,6 +151,11 @@ Object.defineProperties(Request.prototype, {
131
151
  return this.raw.headers.host || this.raw.headers[':authority']
132
152
  }
133
153
  },
154
+ protocol: {
155
+ get () {
156
+ return this.socket.encrypted ? 'https' : 'http'
157
+ }
158
+ },
134
159
  headers: {
135
160
  get () {
136
161
  return this.raw.headers
package/lib/route.js CHANGED
@@ -40,7 +40,8 @@ const {
40
40
  kRequest,
41
41
  kRequestPayloadStream,
42
42
  kDisableRequestLogging,
43
- kSchemaErrorFormatter
43
+ kSchemaErrorFormatter,
44
+ kErrorHandler
44
45
  } = require('./symbols.js')
45
46
 
46
47
  function buildRouting (options) {
@@ -116,7 +117,10 @@ function buildRouting (options) {
116
117
  }
117
118
 
118
119
  // Route management
119
- function route (opts) {
120
+ function route (options) {
121
+ // Since we are mutating/assigning only top level props, it is fine to have a shallow copy using the spread operator
122
+ const opts = { ...options }
123
+
120
124
  throwIfAlreadyStarted('Cannot add route when fastify instance is already started!')
121
125
 
122
126
  if (Array.isArray(opts.method)) {
@@ -210,7 +214,7 @@ function buildRouting (options) {
210
214
  this[kRequest],
211
215
  this[kContentTypeParser],
212
216
  config,
213
- opts.errorHandler || this._errorHandler,
217
+ opts.errorHandler || this[kErrorHandler],
214
218
  opts.bodyLimit,
215
219
  opts.logLevel,
216
220
  opts.logSerializers,
package/lib/symbols.js CHANGED
@@ -38,7 +38,8 @@ const keys = {
38
38
  kDisableRequestLogging: Symbol('fastify.disableRequestLogging'),
39
39
  kPluginNameChain: Symbol('fastify.pluginNameChain'),
40
40
  // This symbol is only meant to be used for fastify tests and should not be used for any other purpose
41
- kTestInternals: Symbol('fastify.testInternals')
41
+ kTestInternals: Symbol('fastify.testInternals'),
42
+ kErrorHandler: Symbol('fastify.errorHandler')
42
43
  }
43
44
 
44
45
  module.exports = keys
package/lib/validation.js CHANGED
@@ -97,6 +97,7 @@ function validate (context, request) {
97
97
 
98
98
  function wrapValidationError (result, dataVar, schemaErrorFormatter) {
99
99
  if (result instanceof Error) {
100
+ result.validationContext = result.validationContext || dataVar
100
101
  return result
101
102
  }
102
103
 
package/lib/warnings.js CHANGED
@@ -8,6 +8,7 @@ const warning = require('fastify-warning')()
8
8
  * - FSTDEP002
9
9
  * - FSTDEP003
10
10
  * - FSTDEP004
11
+ * - FSTDEP005
11
12
  */
12
13
 
13
14
  warning.create('FastifyDeprecation', 'FSTDEP001', 'You are accessing the Node.js core request object via "request.req", Use "request.raw" instead.')
@@ -18,4 +19,6 @@ warning.create('FastifyDeprecation', 'FSTDEP003', 'You are using the legacy Cont
18
19
 
19
20
  warning.create('FastifyDeprecation', 'FSTDEP004', 'You are using the legacy preParsing hook signature. Use the one suggested in the documentation instead.')
20
21
 
22
+ warning.create('FastifyDeprecation', 'FSTDEP005', 'You are accessing the deprecated "request.connection" property. Use "request.socket" instead.')
23
+
21
24
  module.exports = warning
@@ -6,7 +6,7 @@ const {
6
6
  kReplySentOverwritten
7
7
  } = require('./symbols')
8
8
 
9
- const { FST_ERR_PROMISE_NOT_FULLFILLED } = require('./errors')
9
+ const { FST_ERR_PROMISE_NOT_FULFILLED } = require('./errors')
10
10
 
11
11
  function wrapThenable (thenable, reply) {
12
12
  thenable.then(function (payload) {
@@ -27,7 +27,7 @@ function wrapThenable (thenable, reply) {
27
27
  reply.send(err)
28
28
  }
29
29
  } else if (reply[kReplySent] === false) {
30
- reply.log.error({ err: new FST_ERR_PROMISE_NOT_FULLFILLED() }, "Promise may not be fulfilled with 'undefined' when statusCode is not 204")
30
+ reply.log.error({ err: new FST_ERR_PROMISE_NOT_FULFILLED() }, "Promise may not be fulfilled with 'undefined' when statusCode is not 204")
31
31
  }
32
32
  }, function (err) {
33
33
  if (reply[kReplySentOverwritten] === true) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fastify",
3
- "version": "3.4.1",
3
+ "version": "3.7.0",
4
4
  "description": "Fast and low overhead web framework, for Node.js",
5
5
  "main": "fastify.js",
6
6
  "type": "commonjs",
@@ -114,8 +114,8 @@
114
114
  "devDependencies": {
115
115
  "@hapi/joi": "^17.1.1",
116
116
  "@sinonjs/fake-timers": "^6.0.1",
117
- "@types/node": "^14.0.1",
118
117
  "@types/pino": "^6.0.1",
118
+ "@types/node": "^14.10.3",
119
119
  "@typescript-eslint/eslint-plugin": "^2.29.0",
120
120
  "@typescript-eslint/parser": "^2.29.0",
121
121
  "JSONStream": "^1.3.5",
@@ -138,7 +138,7 @@
138
138
  "eslint-plugin-standard": "^4.0.1",
139
139
  "events.once": "^2.0.2",
140
140
  "fast-json-body": "^1.1.0",
141
- "fastify-plugin": "^2.1.0",
141
+ "fastify-plugin": "^3.0.0",
142
142
  "fluent-schema": "^1.0.0",
143
143
  "form-data": "^3.0.0",
144
144
  "frameguard": "^3.1.0",
@@ -152,7 +152,6 @@
152
152
  "pre-commit": "^1.2.2",
153
153
  "proxyquire": "^2.1.3",
154
154
  "pump": "^3.0.0",
155
- "semver": "^7.3.2",
156
155
  "send": "^0.17.1",
157
156
  "serve-static": "^1.14.1",
158
157
  "simple-get": "^4.0.0",
@@ -177,12 +176,13 @@
177
176
  "fastify-warning": "^0.2.0",
178
177
  "find-my-way": "^3.0.0",
179
178
  "flatstr": "^1.0.12",
180
- "light-my-request": "^4.0.2",
179
+ "light-my-request": "^4.2.0",
181
180
  "pino": "^6.2.1",
182
181
  "proxy-addr": "^2.0.5",
183
182
  "readable-stream": "^3.4.0",
184
183
  "rfdc": "^1.1.4",
185
184
  "secure-json-parse": "^2.0.0",
185
+ "semver": "^7.3.2",
186
186
  "tiny-lru": "^7.0.0"
187
187
  },
188
188
  "standard": {
@@ -1214,3 +1214,33 @@ test('route bodyLimit should take precedence over a custom parser bodyLimit', t
1214
1214
  })
1215
1215
  })
1216
1216
  })
1217
+
1218
+ test('should be able to use default parser for extra content type', t => {
1219
+ t.plan(4)
1220
+ const fastify = Fastify()
1221
+ t.tearDown(() => fastify.close())
1222
+
1223
+ fastify.post('/', (request, reply) => {
1224
+ reply.send(request.body)
1225
+ })
1226
+
1227
+ fastify.addContentTypeParser('text/json', { parseAs: 'string' }, fastify.getDefaultJsonParser('ignore', 'ignore'))
1228
+
1229
+ fastify.listen(0, err => {
1230
+ t.error(err)
1231
+
1232
+ sget({
1233
+ method: 'POST',
1234
+ url: 'http://localhost:' + fastify.server.address().port,
1235
+ body: '{"hello":"world"}',
1236
+ headers: {
1237
+ 'Content-Type': 'text/json'
1238
+ }
1239
+ }, (err, response, body) => {
1240
+ t.error(err)
1241
+ t.strictEqual(response.statusCode, 200)
1242
+ t.strictDeepEqual(JSON.parse(body.toString()), { hello: 'world' })
1243
+ fastify.close()
1244
+ })
1245
+ })
1246
+ })
@@ -3,6 +3,7 @@
3
3
  const sget = require('simple-get').concat
4
4
  const { test } = require('tap')
5
5
  const Fastify = require('..')
6
+ const semver = require('semver')
6
7
 
7
8
  process.removeAllListeners('warning')
8
9
 
@@ -129,3 +130,33 @@ test('Should emit a warning when using payload less preParsing hook', t => {
129
130
  })
130
131
  })
131
132
  })
133
+
134
+ if (semver.gte(process.versions.node, '13.0.0')) {
135
+ test('Should emit a warning when accessing request.connection instead of request.socket on Node process greater than 13.0.0', t => {
136
+ t.plan(4)
137
+
138
+ process.on('warning', onWarning)
139
+ function onWarning (warning) {
140
+ t.strictEqual(warning.name, 'FastifyDeprecation')
141
+ t.strictEqual(warning.code, 'FSTDEP005')
142
+ t.strictEqual(warning.message, 'You are accessing the deprecated "request.connection" property. Use "request.socket" instead.')
143
+
144
+ // removed listener before light-my-request emit second warning
145
+ process.removeListener('warning', onWarning)
146
+ }
147
+
148
+ const fastify = Fastify()
149
+
150
+ fastify.get('/', (request, reply) => {
151
+ reply.send(request.connection)
152
+ })
153
+
154
+ fastify.inject({
155
+ method: 'GET',
156
+ path: '/'
157
+ }, (err, res) => {
158
+ t.error(err)
159
+ process.removeListener('warning', onWarning)
160
+ })
161
+ })
162
+ }
@@ -4,8 +4,7 @@ const t = require('tap')
4
4
  const semver = require('semver')
5
5
 
6
6
  if (semver.lt(process.versions.node, '13.3.0')) {
7
- t.skip('Skip because Node version <= 13.3.0')
8
- t.end()
7
+ t.skip('Skip esm because Node version <= 13.3.0')
9
8
  } else {
10
9
  // Node v8 throw a `SyntaxError: Unexpected token import`
11
10
  // even if this branch is never touch in the code,
@@ -17,3 +16,17 @@ if (semver.lt(process.versions.node, '13.3.0')) {
17
16
  })
18
17
  })
19
18
  }
19
+
20
+ if (semver.lt(process.versions.node, '14.13.0')) {
21
+ t.skip('Skip named exports because Node version < 14.13.0')
22
+ } else {
23
+ // Node v8 throw a `SyntaxError: Unexpected token import`
24
+ // even if this branch is never touch in the code,
25
+ // by using `eval` we can avoid this issue.
26
+ // eslint-disable-next-line
27
+ new Function('module', 'return import(module)')('./named-exports.mjs').catch((err) => {
28
+ process.nextTick(() => {
29
+ throw err
30
+ })
31
+ })
32
+ }
@@ -0,0 +1,13 @@
1
+ import t from 'tap'
2
+ import { fastify } from '../../fastify.js'
3
+
4
+ t.test('named exports support', async t => {
5
+ const app = fastify()
6
+
7
+ app.register(import('./plugin.mjs'), { foo: 'bar' })
8
+ app.register(import('./other.mjs'))
9
+
10
+ await app.ready()
11
+
12
+ t.strictEqual(app.foo, 'bar')
13
+ })
@@ -4,7 +4,8 @@ const t = require('tap')
4
4
  const test = t.test
5
5
  const Fastify = require('..')
6
6
  const {
7
- kOptions
7
+ kOptions,
8
+ kErrorHandler
8
9
  } = require('../lib/symbols')
9
10
 
10
11
  test('root fastify instance is an object', t => {
@@ -65,3 +66,34 @@ test('fastify instance get invalid ajv options.plugins', t => {
65
66
  }
66
67
  }))
67
68
  })
69
+
70
+ test('fastify instance should contain default errorHandler', t => {
71
+ t.plan(3)
72
+ const fastify = Fastify()
73
+ t.ok(fastify[kErrorHandler] instanceof Function)
74
+ t.same(fastify.errorHandler, fastify[kErrorHandler])
75
+ t.same(Object.getOwnPropertyDescriptor(fastify, 'errorHandler').set, undefined)
76
+ })
77
+
78
+ test('errorHandler in plugin should be separate from the external one', async t => {
79
+ t.plan(4)
80
+ const fastify = Fastify()
81
+
82
+ fastify.register((instance, opts, next) => {
83
+ const inPluginErrHandler = (_, __, reply) => {
84
+ reply.send({ plugin: 'error-object' })
85
+ }
86
+
87
+ instance.setErrorHandler(inPluginErrHandler)
88
+
89
+ t.notSame(instance.errorHandler, fastify.errorHandler)
90
+ t.equal(instance.errorHandler.name, 'bound inPluginErrHandler')
91
+
92
+ next()
93
+ })
94
+
95
+ await fastify.ready()
96
+
97
+ t.ok(fastify[kErrorHandler] instanceof Function)
98
+ t.same(fastify.errorHandler, fastify[kErrorHandler])
99
+ })
@@ -25,6 +25,9 @@ try {
25
25
  fastify.get('/', function (req, reply) {
26
26
  reply.code(200).send(msg)
27
27
  })
28
+ fastify.get('/proto', function (req, reply) {
29
+ reply.code(200).send({ proto: req.protocol })
30
+ })
28
31
 
29
32
  fastify.listen(0, err => {
30
33
  t.error(err)
@@ -40,4 +43,12 @@ fastify.listen(0, err => {
40
43
  t.strictEqual(res.headers['content-length'], '' + JSON.stringify(msg).length)
41
44
  t.deepEqual(JSON.parse(res.body), msg)
42
45
  })
46
+
47
+ test('https get request without trust proxy - protocol', async (t) => {
48
+ t.plan(2)
49
+
50
+ const url = `https://localhost:${fastify.server.address().port}/proto`
51
+ t.deepEqual(JSON.parse((await h2url.concat({ url })).body), { proto: 'https' })
52
+ t.deepEqual(JSON.parse((await h2url.concat({ url, headers: { 'X-Forwarded-Proto': 'lorem' } })).body), { proto: 'https' })
53
+ })
43
54
  })
@@ -25,6 +25,9 @@ test('https get', t => {
25
25
  fastify.get('/', function (req, reply) {
26
26
  reply.code(200).send({ hello: 'world' })
27
27
  })
28
+ fastify.get('/proto', function (req, reply) {
29
+ reply.code(200).send({ proto: req.protocol })
30
+ })
28
31
  t.pass()
29
32
  } catch (e) {
30
33
  t.fail()
@@ -48,4 +51,27 @@ fastify.listen(0, err => {
48
51
  t.deepEqual(JSON.parse(body), { hello: 'world' })
49
52
  })
50
53
  })
54
+
55
+ test('https get request without trust proxy - protocol', t => {
56
+ t.plan(4)
57
+ sget({
58
+ method: 'GET',
59
+ url: 'https://localhost:' + fastify.server.address().port + '/proto',
60
+ rejectUnauthorized: false
61
+ }, (err, response, body) => {
62
+ t.error(err)
63
+ t.deepEqual(JSON.parse(body), { proto: 'https' })
64
+ })
65
+ sget({
66
+ method: 'GET',
67
+ url: 'https://localhost:' + fastify.server.address().port + '/proto',
68
+ rejectUnauthorized: false,
69
+ headers: {
70
+ 'x-forwarded-proto': 'lorem'
71
+ }
72
+ }, (err, response, body) => {
73
+ t.error(err)
74
+ t.deepEqual(JSON.parse(body), { proto: 'https' })
75
+ })
76
+ })
51
77
  })
@@ -12,7 +12,7 @@ test('Regular request', t => {
12
12
  const req = {
13
13
  method: 'GET',
14
14
  url: '/',
15
- connection: { remoteAddress: 'ip' },
15
+ socket: { remoteAddress: 'ip' },
16
16
  headers
17
17
  }
18
18
  const request = new Request('id', 'params', req, 'query', 'log')
@@ -29,7 +29,7 @@ test('Regular request', t => {
29
29
  t.strictEqual(request.body, null)
30
30
  t.strictEqual(request.method, 'GET')
31
31
  t.strictEqual(request.url, '/')
32
- t.deepEqual(request.connection, req.connection)
32
+ t.deepEqual(request.socket, req.socket)
33
33
  })
34
34
 
35
35
  test('Regular request - hostname from authority', t => {
@@ -40,7 +40,7 @@ test('Regular request - hostname from authority', t => {
40
40
  const req = {
41
41
  method: 'GET',
42
42
  url: '/',
43
- connection: { remoteAddress: 'ip' },
43
+ socket: { remoteAddress: 'ip' },
44
44
  headers
45
45
  }
46
46
 
@@ -58,7 +58,7 @@ test('Regular request - host header has precedence over authority', t => {
58
58
  const req = {
59
59
  method: 'GET',
60
60
  url: '/',
61
- connection: { remoteAddress: 'ip' },
61
+ socket: { remoteAddress: 'ip' },
62
62
  headers
63
63
  }
64
64
  const request = new Request('id', 'params', req, 'query', 'log')
@@ -75,6 +75,9 @@ test('Request with trust proxy', t => {
75
75
  const req = {
76
76
  method: 'GET',
77
77
  url: '/',
78
+ // Some dependencies (proxy-addr, forwarded) still depend on the deprecated
79
+ // .connection property, we use .socket. Include both to satisfy everyone.
80
+ socket: { remoteAddress: 'ip' },
78
81
  connection: { remoteAddress: 'ip' },
79
82
  headers
80
83
  }
@@ -94,7 +97,7 @@ test('Request with trust proxy', t => {
94
97
  t.strictEqual(request.body, null)
95
98
  t.strictEqual(request.method, 'GET')
96
99
  t.strictEqual(request.url, '/')
97
- t.deepEqual(request.connection, req.connection)
100
+ t.deepEqual(request.socket, req.socket)
98
101
  })
99
102
 
100
103
  test('Request with trust proxy - no x-forwarded-host header', t => {
@@ -0,0 +1,43 @@
1
+ 'use strict'
2
+
3
+ const t = require('tap')
4
+ const test = t.test
5
+ const proxyquire = require('proxyquire')
6
+
7
+ test('should output an undefined version in case of package.json not available', t => {
8
+ const Fastify = proxyquire('../..', { fs: { accessSync: () => { throw Error('error') } } })
9
+ t.plan(1)
10
+ const srv = Fastify()
11
+ t.is(srv.version, undefined)
12
+ })
13
+
14
+ test('should output an undefined version in case of package.json is not the fastify one', t => {
15
+ const Fastify = proxyquire('../..', { fs: { accessSync: () => { }, readFileSync: () => JSON.stringify({ name: 'foo', version: '6.6.6' }) } })
16
+ t.plan(1)
17
+ const srv = Fastify()
18
+ t.is(srv.version, undefined)
19
+ })
20
+
21
+ test('should skip the version check if the version is undefined', t => {
22
+ const Fastify = proxyquire('../..', { fs: { accessSync: () => { }, readFileSync: () => JSON.stringify({ name: 'foo', version: '6.6.6' }) } })
23
+ t.plan(3)
24
+ const srv = Fastify()
25
+ t.is(srv.version, undefined)
26
+
27
+ plugin[Symbol.for('skip-override')] = false
28
+ plugin[Symbol.for('plugin-meta')] = {
29
+ name: 'plugin',
30
+ fastify: '>=99.0.0'
31
+ }
32
+
33
+ srv.register(plugin)
34
+
35
+ srv.ready((err) => {
36
+ t.error(err)
37
+ t.pass('everything right')
38
+ })
39
+
40
+ function plugin (instance, opts, next) {
41
+ next()
42
+ }
43
+ })
@@ -351,3 +351,19 @@ test('listen logs the port as info', t => {
351
351
  t.ok(/http:\/\//.test(msgs[0]))
352
352
  })
353
353
  })
354
+
355
+ test('listen when firstArg is string(pipe) and without backlog', async t => {
356
+ t.plan(1)
357
+ const fastify = Fastify()
358
+ t.tearDown(fastify.close.bind(fastify))
359
+ const address = await fastify.listen('\\\\.\\pipe\\testPipe')
360
+ t.is(address, '\\\\.\\pipe\\testPipe')
361
+ })
362
+
363
+ test('listen when firstArg is string(pipe) and with backlog', async t => {
364
+ t.plan(1)
365
+ const fastify = Fastify()
366
+ t.tearDown(fastify.close.bind(fastify))
367
+ const address = await fastify.listen('\\\\.\\pipe\\testPipe', 511)
368
+ t.is(address, '\\\\.\\pipe\\testPipe')
369
+ })
@@ -1423,7 +1423,7 @@ test('should redact the authorization header if so specified', t => {
1423
1423
  headers: req.headers,
1424
1424
  hostname: req.hostname,
1425
1425
  remoteAddress: req.ip,
1426
- remotePort: req.connection.remotePort
1426
+ remotePort: req.socket.remotePort
1427
1427
  }
1428
1428
  }
1429
1429
  }
@@ -817,3 +817,111 @@ test('pluginTimeout default', t => {
817
817
 
818
818
  t.tearDown(clock.uninstall)
819
819
  })
820
+
821
+ test('plugin metadata - version', t => {
822
+ t.plan(1)
823
+ const fastify = Fastify()
824
+
825
+ plugin[Symbol.for('skip-override')] = true
826
+ plugin[Symbol.for('plugin-meta')] = {
827
+ name: 'plugin',
828
+ fastify: '2.0.0'
829
+ }
830
+
831
+ fastify.register(plugin)
832
+
833
+ fastify.ready(() => {
834
+ t.pass('everything right')
835
+ })
836
+
837
+ function plugin (instance, opts, next) {
838
+ next()
839
+ }
840
+ })
841
+
842
+ test('plugin metadata - version range', t => {
843
+ t.plan(1)
844
+ const fastify = Fastify()
845
+
846
+ plugin[Symbol.for('skip-override')] = true
847
+ plugin[Symbol.for('plugin-meta')] = {
848
+ name: 'plugin',
849
+ fastify: '>=2.0.0'
850
+ }
851
+
852
+ fastify.register(plugin)
853
+
854
+ fastify.ready(() => {
855
+ t.pass('everything right')
856
+ })
857
+
858
+ function plugin (instance, opts, next) {
859
+ next()
860
+ }
861
+ })
862
+
863
+ test('plugin metadata - version not matching requirement', t => {
864
+ t.plan(2)
865
+ const fastify = Fastify()
866
+
867
+ plugin[Symbol.for('skip-override')] = true
868
+ plugin[Symbol.for('plugin-meta')] = {
869
+ name: 'plugin',
870
+ fastify: '99.0.0'
871
+ }
872
+
873
+ fastify.register(plugin)
874
+
875
+ fastify.ready((err) => {
876
+ t.ok(err)
877
+ t.equal(err.code, 'FST_ERR_PLUGIN_VERSION_MISMATCH')
878
+ })
879
+
880
+ function plugin (instance, opts, next) {
881
+ next()
882
+ }
883
+ })
884
+
885
+ test('plugin metadata - version not matching requirement 2', t => {
886
+ t.plan(2)
887
+ const fastify = Fastify()
888
+
889
+ plugin[Symbol.for('skip-override')] = true
890
+ plugin[Symbol.for('plugin-meta')] = {
891
+ name: 'plugin',
892
+ fastify: '<=3.0.0'
893
+ }
894
+
895
+ fastify.register(plugin)
896
+
897
+ fastify.ready((err) => {
898
+ t.ok(err)
899
+ t.equal(err.code, 'FST_ERR_PLUGIN_VERSION_MISMATCH')
900
+ })
901
+
902
+ function plugin (instance, opts, next) {
903
+ next()
904
+ }
905
+ })
906
+
907
+ test('plugin metadata - version not matching requirement 3', t => {
908
+ t.plan(2)
909
+ const fastify = Fastify()
910
+
911
+ plugin[Symbol.for('skip-override')] = true
912
+ plugin[Symbol.for('plugin-meta')] = {
913
+ name: 'plugin',
914
+ fastify: '>=99.0.0'
915
+ }
916
+
917
+ fastify.register(plugin)
918
+
919
+ fastify.ready((err) => {
920
+ t.ok(err)
921
+ t.equal(err.code, 'FST_ERR_PLUGIN_VERSION_MISMATCH')
922
+ })
923
+
924
+ function plugin (instance, opts, next) {
925
+ next()
926
+ }
927
+ })