fastify 5.12.0 → 6.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.
- package/README.md +2 -2
- package/build/build-validation.js +20 -34
- package/docs/Guides/Getting-Started.md +2 -2
- package/docs/Reference/Errors.md +5 -3
- package/docs/Reference/Hooks.md +0 -4
- package/docs/Reference/LTS.md +6 -5
- package/docs/Reference/Server.md +8 -88
- package/docs/Reference/TypeScript.md +3 -49
- package/docs/Reference/Warnings.md +4 -11
- package/fastify.d.ts +10 -24
- package/fastify.js +17 -34
- package/lib/config-validator.js +368 -475
- package/lib/errors.js +9 -3
- package/lib/log-controller.js +2 -4
- package/lib/logger-factory.js +1 -1
- package/lib/route.js +4 -9
- package/lib/server.js +2 -3
- package/lib/warnings.js +2 -46
- package/package.json +2 -2
- package/test/404s.test.js +0 -49
- package/test/allow-unsafe-regex.test.js +12 -4
- package/test/case-insensitive.test.js +12 -4
- package/test/custom-querystring-parser.test.js +0 -16
- package/test/hooks.test.js +6 -1
- package/test/http-methods/custom-http-methods.test.js +12 -17
- package/test/http-methods/trace.test.js +1 -1
- package/test/https/custom-https-server.test.js +1 -1
- package/test/internals/errors.test.js +15 -5
- package/test/internals/initial-config.test.js +56 -38
- package/test/internals/logger.test.js +17 -4
- package/test/internals/reply.test.js +1 -1
- package/test/internals/request.test.js +8 -24
- package/test/logger/logging.test.js +2 -121
- package/test/logger/request.test.js +1 -36
- package/test/route-prefix.test.js +46 -18
- package/test/route.1.test.js +2 -2
- package/test/router-options.test.js +25 -523
- package/test/set-error-handler.test.js +7 -9
- package/test/types/errors.tst.ts +2 -1
- package/test/types/fastify.tst.ts +44 -48
- package/test/types/instance.tst.ts +4 -5
- package/test/types/logger.tst.ts +3 -7
- package/test/use-semicolon-delimiter.test.js +0 -60
- package/types/context.d.ts +0 -20
- package/types/errors.d.ts +2 -1
- package/types/instance.d.ts +0 -4
- package/types/logger.d.ts +1 -16
- package/types/plugin.d.ts +0 -9
- package/types/request.d.ts +0 -4
- package/lib/promise.js +0 -23
- package/test/internals/promise.test.js +0 -63
package/lib/errors.js
CHANGED
|
@@ -416,6 +416,12 @@ const codes = {
|
|
|
416
416
|
500,
|
|
417
417
|
TypeError
|
|
418
418
|
),
|
|
419
|
+
FST_ERR_ROUTE_METHOD_ALREADY_SUPPORTED: createError(
|
|
420
|
+
'FST_ERR_ROUTE_METHOD_ALREADY_SUPPORTED',
|
|
421
|
+
'Method "%s" is already supported. Use `overrideExisting: true` to override it.',
|
|
422
|
+
500,
|
|
423
|
+
TypeError
|
|
424
|
+
),
|
|
419
425
|
FST_ERR_ROUTE_METHOD_NOT_SUPPORTED: createError(
|
|
420
426
|
'FST_ERR_ROUTE_METHOD_NOT_SUPPORTED',
|
|
421
427
|
'%s method is not supported.',
|
|
@@ -475,10 +481,10 @@ const codes = {
|
|
|
475
481
|
),
|
|
476
482
|
FST_ERR_REOPENED_SERVER: createError(
|
|
477
483
|
'FST_ERR_REOPENED_SERVER',
|
|
478
|
-
'Fastify is already
|
|
484
|
+
'Fastify is already started'
|
|
479
485
|
),
|
|
480
|
-
|
|
481
|
-
'
|
|
486
|
+
FST_ERR_INSTANCE_ALREADY_STARTED: createError(
|
|
487
|
+
'FST_ERR_INSTANCE_ALREADY_STARTED',
|
|
482
488
|
'Fastify instance is already listening. %s'
|
|
483
489
|
),
|
|
484
490
|
|
package/lib/log-controller.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { defaultInitOptions } = require('./initial-config-validation')
|
|
4
|
-
|
|
5
3
|
/**
|
|
6
4
|
* Internal logger layer that wraps Fastify's log calls with
|
|
7
5
|
* request-lifecycle awareness (disable-check, level selection).
|
|
@@ -20,9 +18,9 @@ class LogController {
|
|
|
20
18
|
*/
|
|
21
19
|
constructor (options) {
|
|
22
20
|
const opts = options || {}
|
|
23
|
-
this.disableRequestLogging = opts.disableRequestLogging ||
|
|
21
|
+
this.disableRequestLogging = opts.disableRequestLogging || false
|
|
24
22
|
this.isDisableRequestLoggingFunction = typeof this.disableRequestLogging === 'function'
|
|
25
|
-
this.requestIdLogLabel = opts.requestIdLogLabel ||
|
|
23
|
+
this.requestIdLogLabel = opts.requestIdLogLabel || 'reqId'
|
|
26
24
|
}
|
|
27
25
|
|
|
28
26
|
/**
|
package/lib/logger-factory.js
CHANGED
|
@@ -132,7 +132,7 @@ function createLogger (options) {
|
|
|
132
132
|
function createLogController (options) {
|
|
133
133
|
const userController = options.logController
|
|
134
134
|
if (!userController) {
|
|
135
|
-
return new LogController(
|
|
135
|
+
return new LogController()
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
if (userController instanceof LogController) {
|
package/lib/route.js
CHANGED
|
@@ -6,6 +6,7 @@ const handleRequest = require('./handle-request.js')
|
|
|
6
6
|
const { onRequestAbortHookRunner, lifecycleHooks, preParsingHookRunner, onTimeoutHookRunner, onRequestHookRunner } = require('./hooks')
|
|
7
7
|
const { normalizeSchema } = require('./schemas')
|
|
8
8
|
const { parseHeadOnSendHandlers } = require('./head-route.js')
|
|
9
|
+
const { defaultInitOptions } = require('./initial-config-validation.js')
|
|
9
10
|
|
|
10
11
|
const {
|
|
11
12
|
compileSchemasForValidation,
|
|
@@ -57,8 +58,6 @@ const {
|
|
|
57
58
|
const { buildErrorHandler } = require('./error-handler')
|
|
58
59
|
const { createChildLogger, defaultChildLoggerFactory } = require('./logger-factory.js')
|
|
59
60
|
const { getGenReqId } = require('./req-id-gen-factory.js')
|
|
60
|
-
const { FSTDEP022 } = require('./warnings')
|
|
61
|
-
|
|
62
61
|
const routerKeys = [
|
|
63
62
|
'allowUnsafeRegex',
|
|
64
63
|
'buildPrettyMeta',
|
|
@@ -663,15 +662,11 @@ function buildRouterOptions (options, defaultOptions) {
|
|
|
663
662
|
? Object.create(null)
|
|
664
663
|
: Object.assign(Object.create(null), options.routerOptions)
|
|
665
664
|
|
|
666
|
-
const usedDeprecatedOptions = routerKeys.filter(key => Object.hasOwn(options, key))
|
|
667
|
-
|
|
668
|
-
if (usedDeprecatedOptions.length > 0) {
|
|
669
|
-
FSTDEP022(usedDeprecatedOptions.join(', '))
|
|
670
|
-
}
|
|
671
|
-
|
|
672
665
|
for (const key of routerKeys) {
|
|
673
666
|
if (!Object.hasOwn(routerOptions, key)) {
|
|
674
|
-
|
|
667
|
+
// defaultInitOptions are non-function default
|
|
668
|
+
// defaultOptions are function default
|
|
669
|
+
routerOptions[key] = options[key] ?? defaultInitOptions.routerOptions[key] ?? defaultOptions[key]
|
|
675
670
|
}
|
|
676
671
|
}
|
|
677
672
|
|
package/lib/server.js
CHANGED
|
@@ -16,7 +16,6 @@ const {
|
|
|
16
16
|
FST_ERR_FORCE_CLOSE_CONNECTIONS_IDLE_NOT_AVAILABLE
|
|
17
17
|
} = require('./errors')
|
|
18
18
|
const noopSet = require('./noop-set')
|
|
19
|
-
const PonyPromise = require('./promise')
|
|
20
19
|
|
|
21
20
|
module.exports.createServer = createServer
|
|
22
21
|
|
|
@@ -106,7 +105,7 @@ function createServer (options, httpHandler) {
|
|
|
106
105
|
if (cb === undefined) {
|
|
107
106
|
const listening = listenPromise.call(this, server, listenOptions)
|
|
108
107
|
return listening.then(address => {
|
|
109
|
-
const { promise, resolve } =
|
|
108
|
+
const { promise, resolve } = Promise.withResolvers()
|
|
110
109
|
if (host === 'localhost') {
|
|
111
110
|
multipleBindings.call(this, server, httpHandler, options, listenOptions, () => {
|
|
112
111
|
this[kState].listening = true
|
|
@@ -277,7 +276,7 @@ function listenPromise (server, listenOptions) {
|
|
|
277
276
|
// skip listen when aborted during ready
|
|
278
277
|
if (this[kState].aborted) return
|
|
279
278
|
|
|
280
|
-
const { promise, resolve, reject } =
|
|
279
|
+
const { promise, resolve, reject } = Promise.withResolvers()
|
|
281
280
|
|
|
282
281
|
const errEventHandler = (err) => {
|
|
283
282
|
cleanup()
|
package/lib/warnings.js
CHANGED
|
@@ -3,13 +3,9 @@
|
|
|
3
3
|
const { createWarning } = require('process-warning')
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Warning codes:
|
|
7
7
|
* - FSTWRN001
|
|
8
8
|
* - FSTSEC001
|
|
9
|
-
* - FSTDEP022
|
|
10
|
-
* - FSTDEP023
|
|
11
|
-
* - FSTDEP024
|
|
12
|
-
* - FSTDEP025
|
|
13
9
|
*
|
|
14
10
|
* Deprecation Codes FSTDEP001 - FSTDEP021 were used by v4 and MUST NOT be reused.
|
|
15
11
|
* - FSTDEP022 - FSTDEP025 are used by v5 and MUST NOT be reused.
|
|
@@ -30,13 +26,6 @@ const FSTWRN003 = createWarning({
|
|
|
30
26
|
unlimited: true
|
|
31
27
|
})
|
|
32
28
|
|
|
33
|
-
const FSTWRN004 = createWarning({
|
|
34
|
-
name: 'FastifyWarning',
|
|
35
|
-
code: 'FSTWRN004',
|
|
36
|
-
message: 'It seems that you are overriding an errorHandler in the same scope, which can lead to subtle bugs. To disable this behavior, set \'allowErrorHandlerOverride\' to false. For more information, visit: https://fastify.dev/docs/latest/Reference/Server/#allowerrorhandleroverride',
|
|
37
|
-
unlimited: true
|
|
38
|
-
})
|
|
39
|
-
|
|
40
29
|
const FSTSEC001 = createWarning({
|
|
41
30
|
name: 'FastifySecurity',
|
|
42
31
|
code: 'FSTSEC001',
|
|
@@ -44,41 +33,8 @@ const FSTSEC001 = createWarning({
|
|
|
44
33
|
unlimited: true
|
|
45
34
|
})
|
|
46
35
|
|
|
47
|
-
const FSTDEP022 = createWarning({
|
|
48
|
-
name: 'FastifyWarning',
|
|
49
|
-
code: 'FSTDEP022',
|
|
50
|
-
message: 'The router options for %s property access is deprecated. Please use "options.routerOptions" instead for accessing router options. The router options will be removed in `fastify@6`.',
|
|
51
|
-
unlimited: true
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
const FSTDEP023 = createWarning({
|
|
55
|
-
name: 'FastifyDeprecation',
|
|
56
|
-
code: 'FSTDEP023',
|
|
57
|
-
message: 'disableRequestLogging option is deprecated. Use the logController option with disableRequestLogging or isLogDisabled override instead. The disableRequestLogging top-level option will be removed in `fastify@6`.',
|
|
58
|
-
unlimited: true
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
const FSTDEP024 = createWarning({
|
|
62
|
-
name: 'FastifyDeprecation',
|
|
63
|
-
code: 'FSTDEP024',
|
|
64
|
-
message: 'requestIdLogLabel option is deprecated. Use the logController option with requestIdLogLabel instead. The requestIdLogLabel top-level option will be removed in `fastify@6`.',
|
|
65
|
-
unlimited: true
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
const FSTDEP025 = createWarning({
|
|
69
|
-
name: 'FastifyDeprecation',
|
|
70
|
-
code: 'FSTDEP025',
|
|
71
|
-
message: 'Calling addHttpMethod for existing method "%s" without { overrideExisting: true } is deprecated. In Fastify v6, this will throw an error.',
|
|
72
|
-
unlimited: true
|
|
73
|
-
})
|
|
74
|
-
|
|
75
36
|
module.exports = {
|
|
76
37
|
FSTWRN001,
|
|
77
38
|
FSTWRN003,
|
|
78
|
-
|
|
79
|
-
FSTSEC001,
|
|
80
|
-
FSTDEP022,
|
|
81
|
-
FSTDEP023,
|
|
82
|
-
FSTDEP024,
|
|
83
|
-
FSTDEP025
|
|
39
|
+
FSTSEC001
|
|
84
40
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fastify",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.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",
|
|
@@ -198,7 +198,7 @@
|
|
|
198
198
|
"tstyche": "^7.0.0",
|
|
199
199
|
"typebox": "^1.0.81",
|
|
200
200
|
"typescript": "~6.0.2",
|
|
201
|
-
"undici": "^
|
|
201
|
+
"undici": "^8.0.0",
|
|
202
202
|
"vary": "^1.1.2",
|
|
203
203
|
"yup": "^1.4.0"
|
|
204
204
|
},
|
package/test/404s.test.js
CHANGED
|
@@ -1984,52 +1984,3 @@ test('hooks are applied to not found handlers /3', async t => {
|
|
|
1984
1984
|
const { statusCode } = await fastify.inject('/')
|
|
1985
1985
|
t.assert.strictEqual(statusCode, 401)
|
|
1986
1986
|
})
|
|
1987
|
-
|
|
1988
|
-
test('should honor disableRequestLogging function for 404', async t => {
|
|
1989
|
-
t.plan(3)
|
|
1990
|
-
|
|
1991
|
-
const Writable = require('node:stream').Writable
|
|
1992
|
-
|
|
1993
|
-
const logStream = new Writable()
|
|
1994
|
-
logStream.logs = []
|
|
1995
|
-
logStream._write = function (chunk, encoding, callback) {
|
|
1996
|
-
this.logs.push(JSON.parse(chunk.toString()))
|
|
1997
|
-
callback()
|
|
1998
|
-
}
|
|
1999
|
-
|
|
2000
|
-
const fastify = Fastify({
|
|
2001
|
-
logger: {
|
|
2002
|
-
level: 'info',
|
|
2003
|
-
stream: logStream
|
|
2004
|
-
},
|
|
2005
|
-
disableRequestLogging: (req) => {
|
|
2006
|
-
// Disable logging for URLs containing 'silent'
|
|
2007
|
-
return req.url.includes('silent')
|
|
2008
|
-
}
|
|
2009
|
-
})
|
|
2010
|
-
|
|
2011
|
-
fastify.get('/', function (req, reply) {
|
|
2012
|
-
reply.send({ hello: 'world' })
|
|
2013
|
-
})
|
|
2014
|
-
|
|
2015
|
-
t.after(() => { fastify.close() })
|
|
2016
|
-
|
|
2017
|
-
// First request to a non-existent route (no 'silent' in URL) - should log
|
|
2018
|
-
const response1 = await fastify.inject({
|
|
2019
|
-
method: 'GET',
|
|
2020
|
-
url: '/not-found'
|
|
2021
|
-
})
|
|
2022
|
-
t.assert.strictEqual(response1.statusCode, 404)
|
|
2023
|
-
|
|
2024
|
-
// Second request to a non-existent route with 'silent' in URL - should not log
|
|
2025
|
-
const response2 = await fastify.inject({
|
|
2026
|
-
method: 'GET',
|
|
2027
|
-
url: '/silent-route'
|
|
2028
|
-
})
|
|
2029
|
-
t.assert.strictEqual(response2.statusCode, 404)
|
|
2030
|
-
|
|
2031
|
-
// Check logs: first request should have logged, second should not
|
|
2032
|
-
// We expect: incoming request, Route not found info, request completed (for first request only)
|
|
2033
|
-
const infoLogs = logStream.logs.filter(log => log.msg && log.msg.includes('Route GET:/not-found not found'))
|
|
2034
|
-
t.assert.strictEqual(infoLogs.length, 1, 'Should log 404 info only for non-silent route')
|
|
2035
|
-
})
|
|
@@ -7,7 +7,9 @@ test('allow unsafe regex', async t => {
|
|
|
7
7
|
t.plan(2)
|
|
8
8
|
|
|
9
9
|
const fastify = Fastify({
|
|
10
|
-
|
|
10
|
+
routerOptions: {
|
|
11
|
+
allowUnsafeRegex: false
|
|
12
|
+
}
|
|
11
13
|
})
|
|
12
14
|
t.after(() => fastify.close())
|
|
13
15
|
|
|
@@ -26,7 +28,9 @@ test('allow unsafe regex not match', async t => {
|
|
|
26
28
|
t.plan(1)
|
|
27
29
|
|
|
28
30
|
const fastify = Fastify({
|
|
29
|
-
|
|
31
|
+
routerOptions: {
|
|
32
|
+
allowUnsafeRegex: false
|
|
33
|
+
}
|
|
30
34
|
})
|
|
31
35
|
t.after(() => fastify.close())
|
|
32
36
|
|
|
@@ -44,7 +48,9 @@ test('allow unsafe regex not safe', (t, done) => {
|
|
|
44
48
|
t.plan(1)
|
|
45
49
|
|
|
46
50
|
const fastify = Fastify({
|
|
47
|
-
|
|
51
|
+
routerOptions: {
|
|
52
|
+
allowUnsafeRegex: false
|
|
53
|
+
}
|
|
48
54
|
})
|
|
49
55
|
t.after(() => fastify.close())
|
|
50
56
|
|
|
@@ -74,7 +80,9 @@ test('allow unsafe regex allow unsafe', async t => {
|
|
|
74
80
|
t.plan(3)
|
|
75
81
|
|
|
76
82
|
const fastify = Fastify({
|
|
77
|
-
|
|
83
|
+
routerOptions: {
|
|
84
|
+
allowUnsafeRegex: true
|
|
85
|
+
}
|
|
78
86
|
})
|
|
79
87
|
t.after(() => fastify.close())
|
|
80
88
|
|
|
@@ -7,7 +7,9 @@ test('case insensitive', async (t) => {
|
|
|
7
7
|
t.plan(3)
|
|
8
8
|
|
|
9
9
|
const fastify = Fastify({
|
|
10
|
-
|
|
10
|
+
routerOptions: {
|
|
11
|
+
caseSensitive: false
|
|
12
|
+
}
|
|
11
13
|
})
|
|
12
14
|
t.after(() => fastify.close())
|
|
13
15
|
|
|
@@ -30,7 +32,9 @@ test('case insensitive inject', async t => {
|
|
|
30
32
|
t.plan(2)
|
|
31
33
|
|
|
32
34
|
const fastify = Fastify({
|
|
33
|
-
|
|
35
|
+
routerOptions: {
|
|
36
|
+
caseSensitive: false
|
|
37
|
+
}
|
|
34
38
|
})
|
|
35
39
|
t.after(() => fastify.close())
|
|
36
40
|
|
|
@@ -55,7 +59,9 @@ test('case insensitive (parametric)', async (t) => {
|
|
|
55
59
|
t.plan(4)
|
|
56
60
|
|
|
57
61
|
const fastify = Fastify({
|
|
58
|
-
|
|
62
|
+
routerOptions: {
|
|
63
|
+
caseSensitive: false
|
|
64
|
+
}
|
|
59
65
|
})
|
|
60
66
|
t.after(() => fastify.close())
|
|
61
67
|
|
|
@@ -81,7 +87,9 @@ test('case insensitive (wildcard)', async (t) => {
|
|
|
81
87
|
t.plan(4)
|
|
82
88
|
|
|
83
89
|
const fastify = Fastify({
|
|
84
|
-
|
|
90
|
+
routerOptions: {
|
|
91
|
+
caseSensitive: false
|
|
92
|
+
}
|
|
85
93
|
})
|
|
86
94
|
t.after(() => fastify.close())
|
|
87
95
|
|
|
@@ -94,22 +94,6 @@ test('Querystring without value', async t => {
|
|
|
94
94
|
t.assert.strictEqual(injectResponse.statusCode, 200)
|
|
95
95
|
})
|
|
96
96
|
|
|
97
|
-
test('Custom querystring parser should be a function', t => {
|
|
98
|
-
t.plan(1)
|
|
99
|
-
|
|
100
|
-
try {
|
|
101
|
-
Fastify({
|
|
102
|
-
querystringParser: 10
|
|
103
|
-
})
|
|
104
|
-
t.assert.fail('Should throw')
|
|
105
|
-
} catch (err) {
|
|
106
|
-
t.assert.strictEqual(
|
|
107
|
-
err.message,
|
|
108
|
-
"querystringParser option should be a function, instead got 'number'"
|
|
109
|
-
)
|
|
110
|
-
}
|
|
111
|
-
})
|
|
112
|
-
|
|
113
97
|
test('Custom querystring parser should be a function', t => {
|
|
114
98
|
t.plan(1)
|
|
115
99
|
|
package/test/hooks.test.js
CHANGED
|
@@ -674,7 +674,12 @@ test('onRoute hook should be called once when prefixTrailingSlash', (t, testDone
|
|
|
674
674
|
let onRouteCalled = 0
|
|
675
675
|
let routePatched = 0
|
|
676
676
|
|
|
677
|
-
const fastify = Fastify({
|
|
677
|
+
const fastify = Fastify({
|
|
678
|
+
exposeHeadRoutes: false,
|
|
679
|
+
routerOptions: {
|
|
680
|
+
ignoreTrailingSlash: false
|
|
681
|
+
}
|
|
682
|
+
})
|
|
678
683
|
|
|
679
684
|
// a plugin that patches route options, similar to fastify-compress
|
|
680
685
|
fastify.register(fp(function myPlugin (instance, opts, next) {
|
|
@@ -113,36 +113,31 @@ test('addHttpMethod rejects fake http method', t => {
|
|
|
113
113
|
t.assert.throws(() => { fastify.addHttpMethod('FOOO') }, /Provided method is invalid!/)
|
|
114
114
|
})
|
|
115
115
|
|
|
116
|
-
test('addHttpMethod
|
|
116
|
+
test('addHttpMethod rejects an implicit override of an existing method', t => {
|
|
117
117
|
const fastify = Fastify()
|
|
118
|
-
const onWarning = warning => {
|
|
119
|
-
t.assert.strictEqual(warning.name, 'FastifyDeprecation')
|
|
120
|
-
t.assert.strictEqual(warning.code, 'FSTDEP025')
|
|
121
|
-
done()
|
|
122
|
-
}
|
|
123
|
-
process.once('warning', onWarning)
|
|
124
118
|
|
|
125
119
|
t.after(() => {
|
|
126
120
|
fastify.close()
|
|
127
|
-
process.removeListener('warning', onWarning)
|
|
128
121
|
})
|
|
129
122
|
|
|
130
|
-
|
|
123
|
+
t.assert.throws(
|
|
124
|
+
() => fastify.addHttpMethod('GET', { hasBody: true }),
|
|
125
|
+
{
|
|
126
|
+
code: 'FST_ERR_ROUTE_METHOD_ALREADY_SUPPORTED',
|
|
127
|
+
message: 'Method "GET" is already supported. Use `overrideExisting: true` to override it.'
|
|
128
|
+
}
|
|
129
|
+
)
|
|
131
130
|
})
|
|
132
131
|
|
|
133
|
-
test('addHttpMethod
|
|
134
|
-
const doNotWarn = () => {
|
|
135
|
-
t.assert.fail('should not warn')
|
|
136
|
-
}
|
|
137
|
-
process.on('warning', doNotWarn)
|
|
138
|
-
|
|
132
|
+
test('addHttpMethod allows an explicit override of an existing method', t => {
|
|
139
133
|
const fastify = Fastify()
|
|
140
134
|
t.after(() => {
|
|
141
135
|
fastify.close()
|
|
142
|
-
process.removeListener('warning', doNotWarn)
|
|
143
136
|
})
|
|
144
137
|
|
|
145
|
-
|
|
138
|
+
t.assert.doesNotThrow(() => {
|
|
139
|
+
fastify.addHttpMethod('POST', { overrideExisting: true })
|
|
140
|
+
})
|
|
146
141
|
})
|
|
147
142
|
|
|
148
143
|
test('addHttpMethod can change an existing method body behavior', async t => {
|
|
@@ -5,7 +5,7 @@ const Fastify = require('../..')
|
|
|
5
5
|
const https = require('node:https')
|
|
6
6
|
const dns = require('node:dns').promises
|
|
7
7
|
const { buildCertificate } = require('../build-certificate')
|
|
8
|
-
const { Agent } = require('undici')
|
|
8
|
+
const { Agent, fetch } = require('undici')
|
|
9
9
|
|
|
10
10
|
async function setup () {
|
|
11
11
|
await buildCertificate()
|
|
@@ -5,7 +5,7 @@ const errors = require('../../lib/errors')
|
|
|
5
5
|
const { readFileSync } = require('node:fs')
|
|
6
6
|
const { resolve } = require('node:path')
|
|
7
7
|
|
|
8
|
-
const expectedErrors =
|
|
8
|
+
const expectedErrors = 95
|
|
9
9
|
|
|
10
10
|
test(`should expose ${expectedErrors} errors`, t => {
|
|
11
11
|
t.plan(1)
|
|
@@ -710,6 +710,16 @@ test('FST_ERR_ROUTE_METHOD_INVALID', t => {
|
|
|
710
710
|
t.assert.ok(error instanceof TypeError)
|
|
711
711
|
})
|
|
712
712
|
|
|
713
|
+
test('FST_ERR_ROUTE_METHOD_ALREADY_SUPPORTED', t => {
|
|
714
|
+
t.plan(5)
|
|
715
|
+
const error = new errors.FST_ERR_ROUTE_METHOD_ALREADY_SUPPORTED('GET')
|
|
716
|
+
t.assert.strictEqual(error.name, 'FastifyError')
|
|
717
|
+
t.assert.strictEqual(error.code, 'FST_ERR_ROUTE_METHOD_ALREADY_SUPPORTED')
|
|
718
|
+
t.assert.strictEqual(error.message, 'Method "GET" is already supported. Use `overrideExisting: true` to override it.')
|
|
719
|
+
t.assert.strictEqual(error.statusCode, 500)
|
|
720
|
+
t.assert.ok(error instanceof TypeError)
|
|
721
|
+
})
|
|
722
|
+
|
|
713
723
|
test('FST_ERR_ROUTE_METHOD_NOT_SUPPORTED', t => {
|
|
714
724
|
t.plan(5)
|
|
715
725
|
const error = new errors.FST_ERR_ROUTE_METHOD_NOT_SUPPORTED()
|
|
@@ -805,16 +815,16 @@ test('FST_ERR_REOPENED_SERVER', t => {
|
|
|
805
815
|
const error = new errors.FST_ERR_REOPENED_SERVER()
|
|
806
816
|
t.assert.strictEqual(error.name, 'FastifyError')
|
|
807
817
|
t.assert.strictEqual(error.code, 'FST_ERR_REOPENED_SERVER')
|
|
808
|
-
t.assert.strictEqual(error.message, 'Fastify is already
|
|
818
|
+
t.assert.strictEqual(error.message, 'Fastify is already started')
|
|
809
819
|
t.assert.strictEqual(error.statusCode, 500)
|
|
810
820
|
t.assert.ok(error instanceof Error)
|
|
811
821
|
})
|
|
812
822
|
|
|
813
|
-
test('
|
|
823
|
+
test('FST_ERR_INSTANCE_ALREADY_STARTED', t => {
|
|
814
824
|
t.plan(5)
|
|
815
|
-
const error = new errors.
|
|
825
|
+
const error = new errors.FST_ERR_INSTANCE_ALREADY_STARTED()
|
|
816
826
|
t.assert.strictEqual(error.name, 'FastifyError')
|
|
817
|
-
t.assert.strictEqual(error.code, '
|
|
827
|
+
t.assert.strictEqual(error.code, 'FST_ERR_INSTANCE_ALREADY_STARTED')
|
|
818
828
|
t.assert.strictEqual(error.message, 'Fastify instance is already listening. %s')
|
|
819
829
|
t.assert.strictEqual(error.statusCode, 500)
|
|
820
830
|
t.assert.ok(error instanceof Error)
|
|
@@ -36,20 +36,21 @@ test('without options passed to Fastify, initialConfig should expose default val
|
|
|
36
36
|
requestTimeout: 0,
|
|
37
37
|
handlerTimeout: 0,
|
|
38
38
|
bodyLimit: 1024 * 1024,
|
|
39
|
-
caseSensitive: true,
|
|
40
|
-
allowUnsafeRegex: false,
|
|
41
|
-
disableRequestLogging: false,
|
|
42
|
-
ignoreTrailingSlash: false,
|
|
43
|
-
ignoreDuplicateSlashes: false,
|
|
44
|
-
maxParamLength: 100,
|
|
45
39
|
onProtoPoisoning: 'error',
|
|
46
40
|
onConstructorPoisoning: 'error',
|
|
47
41
|
pluginTimeout: 10000,
|
|
48
42
|
requestIdHeader: false,
|
|
49
|
-
requestIdLogLabel: 'reqId',
|
|
50
43
|
http2SessionTimeout: 72000,
|
|
51
44
|
exposeHeadRoutes: true,
|
|
52
|
-
|
|
45
|
+
routerOptions: {
|
|
46
|
+
allowUnsafeRegex: false,
|
|
47
|
+
caseSensitive: true,
|
|
48
|
+
constraints: undefined,
|
|
49
|
+
ignoreTrailingSlash: false,
|
|
50
|
+
ignoreDuplicateSlashes: false,
|
|
51
|
+
maxParamLength: 100,
|
|
52
|
+
useSemicolonDelimiter: false
|
|
53
|
+
}
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
t.assert.deepStrictEqual(Fastify().initialConfig, fastifyDefaultOptions)
|
|
@@ -88,65 +89,79 @@ test('Fastify.initialConfig should expose all options', t => {
|
|
|
88
89
|
key: global.context.key,
|
|
89
90
|
cert: global.context.cert
|
|
90
91
|
},
|
|
91
|
-
ignoreTrailingSlash: true,
|
|
92
|
-
ignoreDuplicateSlashes: true,
|
|
93
|
-
maxParamLength: 200,
|
|
94
92
|
connectionTimeout: 0,
|
|
95
93
|
keepAliveTimeout: 72000,
|
|
96
94
|
bodyLimit: 1049600,
|
|
97
95
|
onProtoPoisoning: 'remove',
|
|
98
96
|
serverFactory,
|
|
99
|
-
caseSensitive: true,
|
|
100
|
-
allowUnsafeRegex: false,
|
|
101
97
|
requestIdHeader: 'request-id-alt',
|
|
102
98
|
pluginTimeout: 20000,
|
|
103
|
-
useSemicolonDelimiter: false,
|
|
104
|
-
querystringParser: str => str,
|
|
105
99
|
genReqId: function (req) {
|
|
106
100
|
return reqId++
|
|
107
101
|
},
|
|
108
102
|
loggerInstance: pino({ level: 'info' }),
|
|
109
|
-
constraints: {
|
|
110
|
-
version: versionStrategy
|
|
111
|
-
},
|
|
112
103
|
trustProxy: function myTrustFn (address, hop) {
|
|
113
104
|
return address === '1.2.3.4' || hop === 1
|
|
105
|
+
},
|
|
106
|
+
routerOptions: {
|
|
107
|
+
allowUnsafeRegex: false,
|
|
108
|
+
caseSensitive: true,
|
|
109
|
+
constraints: {
|
|
110
|
+
version: versionStrategy
|
|
111
|
+
},
|
|
112
|
+
ignoreTrailingSlash: true,
|
|
113
|
+
ignoreDuplicateSlashes: true,
|
|
114
|
+
maxParamLength: 200,
|
|
115
|
+
querystringParser: str => str,
|
|
116
|
+
useSemicolonDelimiter: false
|
|
114
117
|
}
|
|
115
118
|
}
|
|
116
119
|
|
|
117
120
|
const fastify = Fastify(options)
|
|
121
|
+
|
|
118
122
|
t.assert.strictEqual(fastify.initialConfig.http2, true)
|
|
119
123
|
t.assert.strictEqual(fastify.initialConfig.https, true, 'for security reason the key cert is hidden')
|
|
120
|
-
t.assert.strictEqual(fastify.initialConfig.ignoreTrailingSlash, true)
|
|
121
|
-
t.assert.strictEqual(fastify.initialConfig.ignoreDuplicateSlashes, true)
|
|
122
|
-
t.assert.strictEqual(fastify.initialConfig.maxParamLength, 200)
|
|
123
124
|
t.assert.strictEqual(fastify.initialConfig.connectionTimeout, 0)
|
|
124
125
|
t.assert.strictEqual(fastify.initialConfig.keepAliveTimeout, 72000)
|
|
125
126
|
t.assert.strictEqual(fastify.initialConfig.bodyLimit, 1049600)
|
|
126
127
|
t.assert.strictEqual(fastify.initialConfig.onProtoPoisoning, 'remove')
|
|
127
|
-
t.assert.strictEqual(fastify.initialConfig.caseSensitive, true)
|
|
128
|
-
t.assert.strictEqual(fastify.initialConfig.useSemicolonDelimiter, false)
|
|
129
|
-
t.assert.strictEqual(fastify.initialConfig.allowUnsafeRegex, false)
|
|
130
128
|
t.assert.strictEqual(fastify.initialConfig.requestIdHeader, 'request-id-alt')
|
|
131
129
|
t.assert.strictEqual(fastify.initialConfig.pluginTimeout, 20000)
|
|
132
|
-
t.assert.ok(fastify.initialConfig.constraints.version)
|
|
133
130
|
|
|
134
131
|
// obfuscated options:
|
|
135
132
|
t.assert.strictEqual(fastify.initialConfig.serverFactory, undefined)
|
|
136
133
|
t.assert.strictEqual(fastify.initialConfig.trustProxy, undefined)
|
|
137
134
|
t.assert.strictEqual(fastify.initialConfig.genReqId, undefined)
|
|
138
135
|
t.assert.strictEqual(fastify.initialConfig.childLoggerFactory, undefined)
|
|
139
|
-
t.assert.strictEqual(fastify.initialConfig.querystringParser, undefined)
|
|
140
136
|
t.assert.strictEqual(fastify.initialConfig.logger, undefined)
|
|
141
137
|
t.assert.strictEqual(fastify.initialConfig.trustProxy, undefined)
|
|
138
|
+
|
|
139
|
+
// router options
|
|
140
|
+
t.assert.strictEqual(fastify.initialConfig.routerOptions.allowUnsafeRegex, false)
|
|
141
|
+
t.assert.strictEqual(fastify.initialConfig.routerOptions.caseSensitive, true)
|
|
142
|
+
t.assert.ok(fastify.initialConfig.routerOptions.constraints.version)
|
|
143
|
+
t.assert.strictEqual(fastify.initialConfig.routerOptions.ignoreTrailingSlash, true)
|
|
144
|
+
t.assert.strictEqual(fastify.initialConfig.routerOptions.ignoreDuplicateSlashes, true)
|
|
145
|
+
t.assert.strictEqual(fastify.initialConfig.routerOptions.maxParamLength, 200)
|
|
146
|
+
t.assert.strictEqual(fastify.initialConfig.routerOptions.querystringParser, undefined)
|
|
147
|
+
t.assert.strictEqual(fastify.initialConfig.routerOptions.useSemicolonDelimiter, false)
|
|
142
148
|
})
|
|
143
149
|
|
|
144
150
|
test('Should throw if you try to modify Fastify.initialConfig', t => {
|
|
145
|
-
t.plan(
|
|
151
|
+
t.plan(8)
|
|
146
152
|
|
|
147
|
-
const fastify = Fastify({ ignoreTrailingSlash: true })
|
|
153
|
+
const fastify = Fastify({ keepAliveTimeout: 1, routerOptions: { ignoreTrailingSlash: true } })
|
|
148
154
|
try {
|
|
149
|
-
fastify.initialConfig.
|
|
155
|
+
fastify.initialConfig.keepAliveTimeout = 2
|
|
156
|
+
t.assert.fail()
|
|
157
|
+
} catch (error) {
|
|
158
|
+
t.assert.ok(error instanceof TypeError)
|
|
159
|
+
t.assert.strictEqual(error.message, "Cannot assign to read only property 'keepAliveTimeout' of object '#<Object>'")
|
|
160
|
+
t.assert.ok(error.stack)
|
|
161
|
+
t.assert.ok(true)
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
fastify.initialConfig.routerOptions.ignoreTrailingSlash = false
|
|
150
165
|
t.assert.fail()
|
|
151
166
|
} catch (error) {
|
|
152
167
|
t.assert.ok(error instanceof TypeError)
|
|
@@ -252,10 +267,12 @@ test('Should not have issues when passing stream options to Pino.js', (t, done)
|
|
|
252
267
|
const stream = split(JSON.parse)
|
|
253
268
|
|
|
254
269
|
const originalOptions = {
|
|
255
|
-
ignoreTrailingSlash: true,
|
|
256
270
|
logger: {
|
|
257
271
|
level: 'trace',
|
|
258
272
|
stream
|
|
273
|
+
},
|
|
274
|
+
routerOptions: {
|
|
275
|
+
ignoreTrailingSlash: true
|
|
259
276
|
}
|
|
260
277
|
}
|
|
261
278
|
|
|
@@ -276,20 +293,21 @@ test('Should not have issues when passing stream options to Pino.js', (t, done)
|
|
|
276
293
|
requestTimeout: 0,
|
|
277
294
|
handlerTimeout: 0,
|
|
278
295
|
bodyLimit: 1024 * 1024,
|
|
279
|
-
caseSensitive: true,
|
|
280
|
-
allowUnsafeRegex: false,
|
|
281
|
-
disableRequestLogging: false,
|
|
282
|
-
ignoreTrailingSlash: true,
|
|
283
|
-
ignoreDuplicateSlashes: false,
|
|
284
|
-
maxParamLength: 100,
|
|
285
296
|
onProtoPoisoning: 'error',
|
|
286
297
|
onConstructorPoisoning: 'error',
|
|
287
298
|
pluginTimeout: 10000,
|
|
288
299
|
requestIdHeader: false,
|
|
289
|
-
requestIdLogLabel: 'reqId',
|
|
290
300
|
http2SessionTimeout: 72000,
|
|
291
301
|
exposeHeadRoutes: true,
|
|
292
|
-
|
|
302
|
+
routerOptions: {
|
|
303
|
+
allowUnsafeRegex: false,
|
|
304
|
+
caseSensitive: true,
|
|
305
|
+
constraints: undefined,
|
|
306
|
+
ignoreTrailingSlash: true,
|
|
307
|
+
ignoreDuplicateSlashes: false,
|
|
308
|
+
maxParamLength: 100,
|
|
309
|
+
useSemicolonDelimiter: false
|
|
310
|
+
}
|
|
293
311
|
})
|
|
294
312
|
} catch (error) {
|
|
295
313
|
t.assert.fail()
|