fastify 5.8.5 → 5.9.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.
- package/SECURITY.md +1 -1
- package/SPONSORS.md +6 -4
- package/docs/Guides/Database.md +0 -28
- package/docs/Guides/Ecosystem.md +13 -2
- package/docs/Guides/Serverless.md +2 -2
- package/docs/Guides/Write-Plugin.md +1 -1
- package/docs/Reference/Encapsulation.md +27 -26
- package/docs/Reference/Errors.md +10 -4
- package/docs/Reference/HTTP2.md +10 -10
- package/docs/Reference/Hooks.md +4 -4
- package/docs/Reference/Index.md +14 -16
- package/docs/Reference/LTS.md +12 -13
- package/docs/Reference/Lifecycle.md +9 -8
- package/docs/Reference/Logging.md +44 -39
- package/docs/Reference/Middleware.md +21 -25
- package/docs/Reference/Principles.md +2 -2
- package/docs/Reference/Reply.md +6 -1
- package/docs/Reference/Request.md +27 -16
- package/docs/Reference/Routes.md +5 -2
- package/docs/Reference/Server.md +31 -3
- package/docs/Reference/Type-Providers.md +29 -5
- package/docs/Reference/Validation-and-Serialization.md +15 -2
- package/docs/Reference/Warnings.md +7 -6
- package/eslint.config.js +7 -2
- package/fastify.d.ts +8 -3
- package/fastify.js +43 -14
- package/lib/content-type-parser.js +13 -1
- package/lib/decorate.js +11 -3
- package/lib/error-handler.js +4 -3
- package/lib/error-serializer.js +59 -59
- package/lib/errors.js +16 -1
- package/lib/four-oh-four.js +14 -9
- package/lib/handle-request.js +11 -5
- package/lib/plugin-override.js +2 -1
- package/lib/plugin-utils.js +5 -5
- package/lib/reply.js +63 -8
- package/lib/request.js +14 -4
- package/lib/route.js +20 -6
- package/lib/schema-controller.js +1 -1
- package/lib/schemas.js +37 -30
- package/lib/symbols.js +3 -1
- package/lib/validation.js +1 -13
- package/lib/warnings.js +3 -3
- package/package.json +13 -15
- package/scripts/validate-ecosystem-links.js +1 -0
- package/test/bundler/esbuild/package.json +1 -1
- package/test/close-pipelining.test.js +1 -2
- package/test/custom-http-server.test.js +38 -0
- package/test/decorator-instance-properties.test.js +63 -0
- package/test/diagnostics-channel/async-error-handler.test.js +74 -0
- package/test/hooks.test.js +23 -0
- package/test/http-methods/get.test.js +1 -1
- package/test/http2/plain.test.js +135 -0
- package/test/http2/secure-with-fallback.test.js +1 -1
- package/test/https/https.test.js +1 -2
- package/test/internals/errors.test.js +31 -1
- package/test/internals/plugin.test.js +3 -1
- package/test/internals/request.test.js +27 -3
- package/test/internals/schema-controller-perf.test.js +33 -0
- package/test/logger/logging.test.js +18 -1
- package/test/logger/options.test.js +38 -1
- package/test/reply-error.test.js +1 -1
- package/test/reply-trailers.test.js +70 -0
- package/test/request-media-type.test.js +105 -0
- package/test/route-prefix.test.js +34 -0
- package/test/router-options.test.js +222 -11
- package/test/schema-serialization.test.js +108 -0
- package/test/schema-validation.test.js +24 -0
- package/test/scripts/validate-ecosystem-links.test.js +40 -57
- package/test/throw.test.js +14 -0
- package/test/trust-proxy.test.js +21 -0
- package/test/types/content-type-parser.tst.ts +70 -0
- package/test/types/{decorate-request-reply.test-d.ts → decorate-request-reply.tst.ts} +4 -4
- package/test/types/{dummy-plugin.ts → dummy-plugin.mts} +1 -1
- package/test/types/errors.tst.ts +91 -0
- package/test/types/fastify.tst.ts +351 -0
- package/test/types/hooks.tst.ts +578 -0
- package/test/types/instance.tst.ts +597 -0
- package/test/types/{logger.test-d.ts → logger.tst.ts} +61 -62
- package/test/types/plugin.tst.ts +96 -0
- package/test/types/register.tst.ts +245 -0
- package/test/types/reply.tst.ts +297 -0
- package/test/types/request.tst.ts +199 -0
- package/test/types/route.tst.ts +576 -0
- package/test/types/{schema.test-d.ts → schema.tst.ts} +22 -22
- package/test/types/{serverFactory.test-d.ts → serverFactory.tst.ts} +4 -4
- package/test/types/tsconfig.json +9 -0
- package/test/types/{type-provider.test-d.ts → type-provider.tst.ts} +256 -250
- package/test/types/using.tst.ts +14 -0
- package/types/errors.d.ts +3 -0
- package/types/request.d.ts +23 -2
- package/test/types/content-type-parser.test-d.ts +0 -72
- package/test/types/errors.test-d.ts +0 -90
- package/test/types/fastify.test-d.ts +0 -352
- package/test/types/hooks.test-d.ts +0 -550
- package/test/types/import.ts +0 -2
- package/test/types/instance.test-d.ts +0 -588
- package/test/types/plugin.test-d.ts +0 -97
- package/test/types/register.test-d.ts +0 -237
- package/test/types/reply.test-d.ts +0 -254
- package/test/types/request.test-d.ts +0 -188
- package/test/types/route.test-d.ts +0 -553
- package/test/types/using.test-d.ts +0 -17
package/fastify.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { Socket } from 'node:net'
|
|
|
6
6
|
import { BuildCompilerFromPool, ValidatorFactory } from '@fastify/ajv-compiler'
|
|
7
7
|
import { FastifyError } from '@fastify/error'
|
|
8
8
|
import { Options as FJSOptions, SerializerFactory } from '@fastify/fast-json-stringify-compiler'
|
|
9
|
-
import { Config as FindMyWayConfig,
|
|
9
|
+
import { ConstraintStrategy, Config as FindMyWayConfig, HTTPVersion } from 'find-my-way'
|
|
10
10
|
import { InjectOptions, CallbackFunc as LightMyRequestCallback, Chain as LightMyRequestChain, Response as LightMyRequestResponse } from 'light-my-request'
|
|
11
11
|
|
|
12
12
|
import { AddContentTypeParser, ConstructorAction, FastifyBodyParser, FastifyContentTypeParser, getDefaultJsonParser, hasContentTypeParser, ProtoAction } from './types/content-type-parser'
|
|
@@ -28,7 +28,7 @@ import { FastifyRegister, FastifyRegisterOptions, RegisterOptions } from './type
|
|
|
28
28
|
import { FastifyReply } from './types/reply'
|
|
29
29
|
import { FastifyRequest, RequestGenericInterface } from './types/request'
|
|
30
30
|
import { RouteGenericInterface, RouteHandler, RouteHandlerMethod, RouteOptions, RouteShorthandMethod, RouteShorthandOptions, RouteShorthandOptionsWithHandler } from './types/route'
|
|
31
|
-
import { FastifySchema,
|
|
31
|
+
import { FastifySchema, FastifySchemaCompiler, FastifySchemaValidationError, FastifySerializerCompiler, SchemaErrorDataVar, SchemaErrorFormatter } from './types/schema'
|
|
32
32
|
import { FastifyServerFactory, FastifyServerFactoryHandler } from './types/server-factory'
|
|
33
33
|
import { FastifyTypeProvider, FastifyTypeProviderDefault, SafePromiseLike } from './types/type-provider'
|
|
34
34
|
import { ContextConfigDefault, HTTPMethods, RawReplyDefaultExpression, RawRequestDefaultExpression, RawServerBase, RawServerDefault, RequestBodyDefault, RequestHeadersDefault, RequestParamsDefault, RequestQuerystringDefault } from './types/utils'
|
|
@@ -90,7 +90,7 @@ declare namespace fastify {
|
|
|
90
90
|
|
|
91
91
|
type TrustProxyFunction = (address: string, hop: number) => boolean
|
|
92
92
|
|
|
93
|
-
export type FastifyRouterOptions<RawServer extends RawServerBase> = Omit<FindMyWayConfigForServer<RawServer>, 'defaultRoute' | 'onBadUrl' | 'querystringParser'> & {
|
|
93
|
+
export type FastifyRouterOptions<RawServer extends RawServerBase> = Omit<FindMyWayConfigForServer<RawServer>, 'defaultRoute' | 'onBadUrl' | 'onMaxParamLength' | 'querystringParser'> & {
|
|
94
94
|
defaultRoute?: (
|
|
95
95
|
req: RawRequestDefaultExpression<RawServer>,
|
|
96
96
|
res: RawReplyDefaultExpression<RawServer>
|
|
@@ -100,6 +100,11 @@ declare namespace fastify {
|
|
|
100
100
|
req: RawRequestDefaultExpression<RawServer>,
|
|
101
101
|
res: RawReplyDefaultExpression<RawServer>
|
|
102
102
|
) => void,
|
|
103
|
+
onMaxParamLength?: (
|
|
104
|
+
path: string,
|
|
105
|
+
req: RawRequestDefaultExpression<RawServer>,
|
|
106
|
+
res: RawReplyDefaultExpression<RawServer>
|
|
107
|
+
) => void,
|
|
103
108
|
querystringParser?: (str: string) => { [key: string]: unknown }
|
|
104
109
|
}
|
|
105
110
|
|
package/fastify.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const VERSION = '5.
|
|
3
|
+
const VERSION = '5.9.0'
|
|
4
4
|
|
|
5
5
|
const Avvio = require('avvio')
|
|
6
6
|
const http = require('node:http')
|
|
@@ -63,6 +63,7 @@ const { defaultInitOptions } = getSecuredInitialConfig
|
|
|
63
63
|
const {
|
|
64
64
|
FST_ERR_ASYNC_CONSTRAINT,
|
|
65
65
|
FST_ERR_BAD_URL,
|
|
66
|
+
FST_ERR_MAX_PARAM_LENGTH,
|
|
66
67
|
FST_ERR_OPTIONS_NOT_OBJ,
|
|
67
68
|
FST_ERR_QSP_NOT_FN,
|
|
68
69
|
FST_ERR_SCHEMA_CONTROLLER_BUCKET_OPT_NOT_FN,
|
|
@@ -92,7 +93,7 @@ function fastify (serverOptions) {
|
|
|
92
93
|
disableRequestLogging,
|
|
93
94
|
hasLogger,
|
|
94
95
|
initialConfig
|
|
95
|
-
} = processOptions(serverOptions, defaultRoute, onBadUrl)
|
|
96
|
+
} = processOptions(serverOptions, defaultRoute, onBadUrl, onMaxParamLength)
|
|
96
97
|
|
|
97
98
|
// Default router
|
|
98
99
|
const router = buildRouting(options.routerOptions)
|
|
@@ -381,8 +382,7 @@ function fastify (serverOptions) {
|
|
|
381
382
|
hookRunnerApplication('preClose', fastify[kAvvioBoot], fastify, function () {
|
|
382
383
|
if (fastify[kState].listening) {
|
|
383
384
|
/* istanbul ignore next: Cannot test this without Node.js core support */
|
|
384
|
-
if (forceCloseConnections === 'idle') {
|
|
385
|
-
// Not needed in Node 19
|
|
385
|
+
if (forceCloseConnections === 'idle' && options.serverFactory) {
|
|
386
386
|
instance.server.closeIdleConnections()
|
|
387
387
|
/* istanbul ignore next: Cannot test this without Node.js core support */
|
|
388
388
|
} else if (serverHasCloseAllConnections && forceCloseConnections) {
|
|
@@ -423,8 +423,8 @@ function fastify (serverOptions) {
|
|
|
423
423
|
})
|
|
424
424
|
})
|
|
425
425
|
|
|
426
|
-
// Create bad URL context
|
|
427
|
-
const
|
|
426
|
+
// Create route event (bad URL, max param length, etc) context
|
|
427
|
+
const routeEventContext = new Context({
|
|
428
428
|
server: fastify,
|
|
429
429
|
config: {}
|
|
430
430
|
})
|
|
@@ -637,10 +637,10 @@ function fastify (serverOptions) {
|
|
|
637
637
|
|
|
638
638
|
function onBadUrl (path, req, res) {
|
|
639
639
|
if (options.frameworkErrors) {
|
|
640
|
-
const id = getGenReqId(
|
|
641
|
-
const childLogger = createChildLogger(
|
|
640
|
+
const id = getGenReqId(routeEventContext.server, req)
|
|
641
|
+
const childLogger = createChildLogger(routeEventContext, options.logger, req, id)
|
|
642
642
|
|
|
643
|
-
const request = new Request(id, null, req, null, childLogger,
|
|
643
|
+
const request = new Request(id, null, req, null, childLogger, routeEventContext)
|
|
644
644
|
const reply = new Reply(res, request, childLogger)
|
|
645
645
|
|
|
646
646
|
const resolvedDisableRequestLogging = typeof disableRequestLogging === 'function' ? disableRequestLogging(req) : disableRequestLogging
|
|
@@ -663,15 +663,43 @@ function fastify (serverOptions) {
|
|
|
663
663
|
res.end(body)
|
|
664
664
|
}
|
|
665
665
|
|
|
666
|
+
function onMaxParamLength (path, req, res) {
|
|
667
|
+
if (options.frameworkErrors) {
|
|
668
|
+
const id = getGenReqId(routeEventContext.server, req)
|
|
669
|
+
const childLogger = createChildLogger(routeEventContext, options.logger, req, id)
|
|
670
|
+
|
|
671
|
+
const request = new Request(id, null, req, null, childLogger, routeEventContext)
|
|
672
|
+
const reply = new Reply(res, request, childLogger)
|
|
673
|
+
|
|
674
|
+
const resolvedDisableRequestLogging = typeof disableRequestLogging === 'function' ? disableRequestLogging(req) : disableRequestLogging
|
|
675
|
+
if (resolvedDisableRequestLogging === false) {
|
|
676
|
+
childLogger.info({ req: request }, 'incoming request')
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
return options.frameworkErrors(new FST_ERR_MAX_PARAM_LENGTH(path), request, reply)
|
|
680
|
+
}
|
|
681
|
+
const body = JSON.stringify({
|
|
682
|
+
error: 'Bad Request',
|
|
683
|
+
code: 'FST_ERR_MAX_PARAM_LENGTH',
|
|
684
|
+
message: `'${path}' is exceeding the max param length`,
|
|
685
|
+
statusCode: 414
|
|
686
|
+
})
|
|
687
|
+
res.writeHead(414, {
|
|
688
|
+
'Content-Type': 'application/json',
|
|
689
|
+
'Content-Length': Buffer.byteLength(body)
|
|
690
|
+
})
|
|
691
|
+
res.end(body)
|
|
692
|
+
}
|
|
693
|
+
|
|
666
694
|
function buildAsyncConstraintCallback (isAsync, req, res) {
|
|
667
695
|
if (isAsync === false) return undefined
|
|
668
696
|
return function onAsyncConstraintError (err) {
|
|
669
697
|
if (err) {
|
|
670
698
|
if (options.frameworkErrors) {
|
|
671
|
-
const id = getGenReqId(
|
|
672
|
-
const childLogger = createChildLogger(
|
|
699
|
+
const id = getGenReqId(routeEventContext.server, req)
|
|
700
|
+
const childLogger = createChildLogger(routeEventContext, options.logger, req, id)
|
|
673
701
|
|
|
674
|
-
const request = new Request(id, null, req, null, childLogger,
|
|
702
|
+
const request = new Request(id, null, req, null, childLogger, routeEventContext)
|
|
675
703
|
const reply = new Reply(res, request, childLogger)
|
|
676
704
|
|
|
677
705
|
const resolvedDisableRequestLogging = typeof disableRequestLogging === 'function' ? disableRequestLogging(req) : disableRequestLogging
|
|
@@ -748,7 +776,7 @@ function fastify (serverOptions) {
|
|
|
748
776
|
if (!options.allowErrorHandlerOverride && this[kErrorHandlerAlreadySet]) {
|
|
749
777
|
throw new FST_ERR_ERROR_HANDLER_ALREADY_SET()
|
|
750
778
|
} else if (this[kErrorHandlerAlreadySet]) {
|
|
751
|
-
FSTWRN004(
|
|
779
|
+
FSTWRN004()
|
|
752
780
|
}
|
|
753
781
|
|
|
754
782
|
this[kErrorHandlerAlreadySet] = true
|
|
@@ -821,7 +849,7 @@ function fastify (serverOptions) {
|
|
|
821
849
|
}
|
|
822
850
|
}
|
|
823
851
|
|
|
824
|
-
function processOptions (options, defaultRoute, onBadUrl) {
|
|
852
|
+
function processOptions (options, defaultRoute, onBadUrl, onMaxParamLength) {
|
|
825
853
|
// Options validations
|
|
826
854
|
if (options && typeof options !== 'object') {
|
|
827
855
|
throw new FST_ERR_OPTIONS_NOT_OBJ()
|
|
@@ -890,6 +918,7 @@ function processOptions (options, defaultRoute, onBadUrl) {
|
|
|
890
918
|
options.routerOptions = buildRouterOptions(options, {
|
|
891
919
|
defaultRoute,
|
|
892
920
|
onBadUrl,
|
|
921
|
+
onMaxParamLength,
|
|
893
922
|
ignoreTrailingSlash: defaultInitOptions.ignoreTrailingSlash,
|
|
894
923
|
ignoreDuplicateSlashes: defaultInitOptions.ignoreDuplicateSlashes,
|
|
895
924
|
maxParamLength: defaultInitOptions.maxParamLength,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { AsyncResource } = require('node:async_hooks')
|
|
4
|
-
const { FifoMap: Fifo } = require('toad-cache')
|
|
4
|
+
const { FifoMap: Fifo, LruMap: Lru } = require('toad-cache')
|
|
5
5
|
const { parse: secureJsonParse } = require('secure-json-parse')
|
|
6
6
|
const ContentType = require('./content-type')
|
|
7
7
|
const {
|
|
@@ -39,6 +39,15 @@ function ContentTypeParser (bodyLimit, onProtoPoisoning, onConstructorPoisoning)
|
|
|
39
39
|
this.parserList = ['application/json', 'text/plain']
|
|
40
40
|
this.parserRegExpList = []
|
|
41
41
|
this.cache = new Fifo(100)
|
|
42
|
+
this.ctCache = new Lru(100)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
ContentTypeParser.prototype.getContentType = function (raw) {
|
|
46
|
+
let ct = this.ctCache.get(raw)
|
|
47
|
+
if (ct !== undefined) return ct
|
|
48
|
+
ct = new ContentType(raw)
|
|
49
|
+
this.ctCache.set(raw, ct)
|
|
50
|
+
return ct
|
|
42
51
|
}
|
|
43
52
|
|
|
44
53
|
ContentTypeParser.prototype.add = function (contentType, opts, parserFn) {
|
|
@@ -118,6 +127,8 @@ ContentTypeParser.prototype.existingParser = function (contentType) {
|
|
|
118
127
|
|
|
119
128
|
ContentTypeParser.prototype.getParser = function (contentType) {
|
|
120
129
|
if (typeof contentType === 'string') {
|
|
130
|
+
const cached = this.cache.get(contentType)
|
|
131
|
+
if (cached !== undefined) return cached
|
|
121
132
|
contentType = new ContentType(contentType)
|
|
122
133
|
}
|
|
123
134
|
const ct = contentType.toString()
|
|
@@ -158,6 +169,7 @@ ContentTypeParser.prototype.removeAll = function () {
|
|
|
158
169
|
this.parserRegExpList = []
|
|
159
170
|
this.parserList = []
|
|
160
171
|
this.cache = new Fifo(100)
|
|
172
|
+
this.ctCache = new Lru(100)
|
|
161
173
|
}
|
|
162
174
|
|
|
163
175
|
ContentTypeParser.prototype.remove = function (contentType) {
|
package/lib/decorate.js
CHANGED
|
@@ -47,7 +47,7 @@ function getInstanceDecorator (name) {
|
|
|
47
47
|
|
|
48
48
|
function decorateConstructor (konstructor, name, fn, dependencies) {
|
|
49
49
|
const instance = konstructor.prototype
|
|
50
|
-
if (Object.hasOwn(instance, name) || hasKey(konstructor, name)) {
|
|
50
|
+
if (Object.hasOwn(instance, name) || hasKey(konstructor, name) || hasInstanceProperty(konstructor, name)) {
|
|
51
51
|
throw new FST_ERR_DEC_ALREADY_PRESENT(name)
|
|
52
52
|
}
|
|
53
53
|
|
|
@@ -87,19 +87,27 @@ function checkExistence (instance, name) {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
function hasKey (fn, name) {
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
return fn.props ? fn.props.some(p => p.key === name) : false
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function hasInstanceProperty (konstructor, name) {
|
|
94
|
+
let k = konstructor
|
|
95
|
+
while (k) {
|
|
96
|
+
if (k.instanceProperties && k.instanceProperties.has(name)) return true
|
|
97
|
+
k = k.parent
|
|
92
98
|
}
|
|
93
99
|
return false
|
|
94
100
|
}
|
|
95
101
|
|
|
96
102
|
function checkRequestExistence (name) {
|
|
97
103
|
if (name && hasKey(this[kRequest], name)) return true
|
|
104
|
+
if (name && hasInstanceProperty(this[kRequest], name)) return true
|
|
98
105
|
return checkExistence(this[kRequest].prototype, name)
|
|
99
106
|
}
|
|
100
107
|
|
|
101
108
|
function checkReplyExistence (name) {
|
|
102
109
|
if (name && hasKey(this[kReply], name)) return true
|
|
110
|
+
if (name && hasInstanceProperty(this[kReply], name)) return true
|
|
103
111
|
return checkExistence(this[kReply].prototype, name)
|
|
104
112
|
}
|
|
105
113
|
|
package/lib/error-handler.js
CHANGED
|
@@ -8,7 +8,8 @@ const {
|
|
|
8
8
|
kReplyNextErrorHandler,
|
|
9
9
|
kReplyIsRunningOnErrorHook,
|
|
10
10
|
kRouteContext,
|
|
11
|
-
kDisableRequestLogging
|
|
11
|
+
kDisableRequestLogging,
|
|
12
|
+
kDiagnosticsStore
|
|
12
13
|
} = require('./symbols.js')
|
|
13
14
|
|
|
14
15
|
const {
|
|
@@ -19,7 +20,6 @@ const {
|
|
|
19
20
|
const { getSchemaSerializer } = require('./schemas')
|
|
20
21
|
|
|
21
22
|
const serializeError = require('./error-serializer')
|
|
22
|
-
|
|
23
23
|
const rootErrorHandler = {
|
|
24
24
|
func: defaultErrorHandler,
|
|
25
25
|
toJSON () {
|
|
@@ -69,7 +69,8 @@ function handleError (reply, error, cb) {
|
|
|
69
69
|
const result = func(error, reply.request, reply)
|
|
70
70
|
if (result !== undefined) {
|
|
71
71
|
if (result !== null && typeof result.then === 'function') {
|
|
72
|
-
|
|
72
|
+
const store = reply[kDiagnosticsStore] || null
|
|
73
|
+
wrapThenable(result, reply, store)
|
|
73
74
|
} else {
|
|
74
75
|
reply.send(result)
|
|
75
76
|
}
|
package/lib/error-serializer.js
CHANGED
|
@@ -40,93 +40,93 @@ const asInteger = serializer.asInteger.bind(serializer)
|
|
|
40
40
|
const JSON_STR_NULL = 'null'
|
|
41
41
|
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const obj = (input && typeof input.toJSON === 'function')
|
|
43
|
+
// #
|
|
44
|
+
function anonymous0 (input) {
|
|
45
|
+
const obj = (input && typeof input.toJSON === 'function')
|
|
47
46
|
? input.toJSON()
|
|
48
47
|
: input
|
|
49
48
|
|
|
50
|
-
|
|
49
|
+
if (obj === null) return JSON_STR_EMPTY_OBJECT
|
|
50
|
+
let json = ''
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
let
|
|
54
|
-
let addComma = false
|
|
52
|
+
json += JSON_STR_BEGIN_OBJECT
|
|
53
|
+
let addComma_0 = false
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
const value_statusCode_1 = obj["statusCode"]
|
|
56
|
+
if (value_statusCode_1 !== undefined) {
|
|
57
|
+
!addComma_0 && (addComma_0 = true) || (json += JSON_STR_COMMA)
|
|
58
|
+
json += "\"statusCode\":"
|
|
59
|
+
json += asNumber(value_statusCode_1)
|
|
60
|
+
}
|
|
62
61
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (typeof
|
|
69
|
-
if (
|
|
62
|
+
const value_code_2 = obj["code"]
|
|
63
|
+
if (value_code_2 !== undefined) {
|
|
64
|
+
!addComma_0 && (addComma_0 = true) || (json += JSON_STR_COMMA)
|
|
65
|
+
json += "\"code\":"
|
|
66
|
+
|
|
67
|
+
if (typeof value_code_2 !== 'string') {
|
|
68
|
+
if (value_code_2 === null) {
|
|
70
69
|
json += JSON_STR_EMPTY_STRING
|
|
71
|
-
} else if (
|
|
72
|
-
json += JSON_STR_QUOTE +
|
|
73
|
-
} else if (
|
|
74
|
-
json += asString(
|
|
70
|
+
} else if (value_code_2 instanceof Date) {
|
|
71
|
+
json += JSON_STR_QUOTE + value_code_2.toISOString() + JSON_STR_QUOTE
|
|
72
|
+
} else if (value_code_2 instanceof RegExp) {
|
|
73
|
+
json += asString(value_code_2.source)
|
|
75
74
|
} else {
|
|
76
|
-
json += asString(
|
|
75
|
+
json += asString(value_code_2.toString())
|
|
77
76
|
}
|
|
78
77
|
} else {
|
|
79
|
-
json += asString(
|
|
78
|
+
json += asString(value_code_2)
|
|
80
79
|
}
|
|
81
80
|
|
|
82
|
-
|
|
81
|
+
}
|
|
83
82
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if (typeof
|
|
90
|
-
if (
|
|
83
|
+
const value_error_3 = obj["error"]
|
|
84
|
+
if (value_error_3 !== undefined) {
|
|
85
|
+
!addComma_0 && (addComma_0 = true) || (json += JSON_STR_COMMA)
|
|
86
|
+
json += "\"error\":"
|
|
87
|
+
|
|
88
|
+
if (typeof value_error_3 !== 'string') {
|
|
89
|
+
if (value_error_3 === null) {
|
|
91
90
|
json += JSON_STR_EMPTY_STRING
|
|
92
|
-
} else if (
|
|
93
|
-
json += JSON_STR_QUOTE +
|
|
94
|
-
} else if (
|
|
95
|
-
json += asString(
|
|
91
|
+
} else if (value_error_3 instanceof Date) {
|
|
92
|
+
json += JSON_STR_QUOTE + value_error_3.toISOString() + JSON_STR_QUOTE
|
|
93
|
+
} else if (value_error_3 instanceof RegExp) {
|
|
94
|
+
json += asString(value_error_3.source)
|
|
96
95
|
} else {
|
|
97
|
-
json += asString(
|
|
96
|
+
json += asString(value_error_3.toString())
|
|
98
97
|
}
|
|
99
98
|
} else {
|
|
100
|
-
json += asString(
|
|
99
|
+
json += asString(value_error_3)
|
|
101
100
|
}
|
|
102
101
|
|
|
103
|
-
|
|
102
|
+
}
|
|
104
103
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
if (typeof
|
|
111
|
-
if (
|
|
104
|
+
const value_message_4 = obj["message"]
|
|
105
|
+
if (value_message_4 !== undefined) {
|
|
106
|
+
!addComma_0 && (addComma_0 = true) || (json += JSON_STR_COMMA)
|
|
107
|
+
json += "\"message\":"
|
|
108
|
+
|
|
109
|
+
if (typeof value_message_4 !== 'string') {
|
|
110
|
+
if (value_message_4 === null) {
|
|
112
111
|
json += JSON_STR_EMPTY_STRING
|
|
113
|
-
} else if (
|
|
114
|
-
json += JSON_STR_QUOTE +
|
|
115
|
-
} else if (
|
|
116
|
-
json += asString(
|
|
112
|
+
} else if (value_message_4 instanceof Date) {
|
|
113
|
+
json += JSON_STR_QUOTE + value_message_4.toISOString() + JSON_STR_QUOTE
|
|
114
|
+
} else if (value_message_4 instanceof RegExp) {
|
|
115
|
+
json += asString(value_message_4.source)
|
|
117
116
|
} else {
|
|
118
|
-
json += asString(
|
|
117
|
+
json += asString(value_message_4.toString())
|
|
119
118
|
}
|
|
120
119
|
} else {
|
|
121
|
-
json += asString(
|
|
120
|
+
json += asString(value_message_4)
|
|
122
121
|
}
|
|
123
122
|
|
|
124
|
-
|
|
123
|
+
}
|
|
125
124
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
125
|
+
json += JSON_STR_END_OBJECT
|
|
129
126
|
|
|
127
|
+
return json
|
|
128
|
+
}
|
|
129
|
+
|
|
130
130
|
const main = anonymous0
|
|
131
131
|
return main
|
|
132
132
|
|
package/lib/errors.js
CHANGED
|
@@ -364,6 +364,12 @@ const codes = {
|
|
|
364
364
|
400,
|
|
365
365
|
URIError
|
|
366
366
|
),
|
|
367
|
+
FST_ERR_MAX_PARAM_LENGTH: createError(
|
|
368
|
+
'FST_ERR_MAX_PARAM_LENGTH',
|
|
369
|
+
"'%s' is exceeding the max param length",
|
|
370
|
+
414,
|
|
371
|
+
URIError
|
|
372
|
+
),
|
|
367
373
|
FST_ERR_ASYNC_CONSTRAINT: createError(
|
|
368
374
|
'FST_ERR_ASYNC_CONSTRAINT',
|
|
369
375
|
'Unexpected error from async constraint',
|
|
@@ -408,6 +414,12 @@ const codes = {
|
|
|
408
414
|
'%s method is not supported.',
|
|
409
415
|
500
|
|
410
416
|
),
|
|
417
|
+
FST_ERR_ROUTE_LOG_LEVEL_INVALID: createError(
|
|
418
|
+
'FST_ERR_ROUTE_LOG_LEVEL_INVALID',
|
|
419
|
+
"Log level for '%s:%s' route must be a valid logger level. Received: '%s'",
|
|
420
|
+
500,
|
|
421
|
+
TypeError
|
|
422
|
+
),
|
|
411
423
|
FST_ERR_ROUTE_BODY_VALIDATION_SCHEMA_NOT_SUPPORTED: createError(
|
|
412
424
|
'FST_ERR_ROUTE_BODY_VALIDATION_SCHEMA_NOT_SUPPORTED',
|
|
413
425
|
'Body validation schema for %s:%s route is not supported!',
|
|
@@ -470,7 +482,10 @@ const codes = {
|
|
|
470
482
|
500,
|
|
471
483
|
TypeError
|
|
472
484
|
),
|
|
473
|
-
|
|
485
|
+
FST_ERR_PLUGIN_DEPENDENCY_NOT_REGISTERED: createError(
|
|
486
|
+
'FST_ERR_PLUGIN_DEPENDENCY_NOT_REGISTERED',
|
|
487
|
+
"The dependency '%s' of plugin '%s' is not registered"
|
|
488
|
+
),
|
|
474
489
|
/**
|
|
475
490
|
* Avvio Errors
|
|
476
491
|
*/
|
package/lib/four-oh-four.js
CHANGED
|
@@ -32,8 +32,12 @@ function fourOhFour (options) {
|
|
|
32
32
|
const { logger, disableRequestLogging } = options
|
|
33
33
|
|
|
34
34
|
// 404 router, used for handling encapsulated 404 handlers
|
|
35
|
-
const router = FindMyWay({
|
|
36
|
-
|
|
35
|
+
const router = FindMyWay({
|
|
36
|
+
onBadUrl: createRouteEventHandler(),
|
|
37
|
+
onMaxParamLength: createRouteEventHandler(),
|
|
38
|
+
defaultRoute: fourOhFourFallBack
|
|
39
|
+
})
|
|
40
|
+
let _routeEventHandler = null
|
|
37
41
|
|
|
38
42
|
return { router, setNotFoundHandler, setContext, arrange404 }
|
|
39
43
|
|
|
@@ -43,6 +47,7 @@ function fourOhFour (options) {
|
|
|
43
47
|
instance[kCanSetNotFoundHandler] = true
|
|
44
48
|
// we need to bind instance for the context
|
|
45
49
|
router.onBadUrl = router.onBadUrl.bind(instance)
|
|
50
|
+
router.onMaxParamLength = router.onMaxParamLength.bind(instance)
|
|
46
51
|
router.defaultRoute = router.defaultRoute.bind(instance)
|
|
47
52
|
}
|
|
48
53
|
|
|
@@ -60,15 +65,15 @@ function fourOhFour (options) {
|
|
|
60
65
|
})
|
|
61
66
|
}
|
|
62
67
|
|
|
63
|
-
function
|
|
64
|
-
return function
|
|
68
|
+
function createRouteEventHandler () {
|
|
69
|
+
return function onRouteEvent (path, req, res) {
|
|
65
70
|
const fourOhFourContext = this[kFourOhFourLevelInstance][kFourOhFourContext]
|
|
66
71
|
const id = getGenReqId(fourOhFourContext.server, req)
|
|
67
72
|
const childLogger = createChildLogger(fourOhFourContext, logger, req, id)
|
|
68
73
|
const request = new Request(id, null, req, null, childLogger, fourOhFourContext)
|
|
69
74
|
const reply = new Reply(res, request, childLogger)
|
|
70
75
|
|
|
71
|
-
|
|
76
|
+
_routeEventHandler(request, reply)
|
|
72
77
|
}
|
|
73
78
|
}
|
|
74
79
|
|
|
@@ -121,12 +126,12 @@ function fourOhFour (options) {
|
|
|
121
126
|
if (handler) {
|
|
122
127
|
this[kFourOhFourLevelInstance][kCanSetNotFoundHandler] = false
|
|
123
128
|
handler = handler.bind(this)
|
|
124
|
-
// update
|
|
125
|
-
|
|
129
|
+
// update route event handler
|
|
130
|
+
_routeEventHandler = handler
|
|
126
131
|
} else {
|
|
127
132
|
handler = basic404
|
|
128
|
-
// update
|
|
129
|
-
|
|
133
|
+
// update route event handler
|
|
134
|
+
_routeEventHandler = basic404
|
|
130
135
|
}
|
|
131
136
|
|
|
132
137
|
this.after((notHandledErr, done) => {
|
package/lib/handle-request.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const diagnostics = require('node:diagnostics_channel')
|
|
4
|
-
const ContentType = require('./content-type')
|
|
5
4
|
const wrapThenable = require('./wrap-thenable')
|
|
6
5
|
const { validate: validateSchema } = require('./validation')
|
|
7
6
|
const { preValidationHookRunner, preHandlerHookRunner } = require('./hooks')
|
|
@@ -11,7 +10,9 @@ const {
|
|
|
11
10
|
kReplyIsError,
|
|
12
11
|
kRouteContext,
|
|
13
12
|
kFourOhFourContext,
|
|
14
|
-
kSupportedHTTPMethods
|
|
13
|
+
kSupportedHTTPMethods,
|
|
14
|
+
kRequestContentType,
|
|
15
|
+
kDiagnosticsStore
|
|
15
16
|
} = require('./symbols')
|
|
16
17
|
|
|
17
18
|
const channels = diagnostics.tracingChannel('fastify.request.handler')
|
|
@@ -51,13 +52,17 @@ function handleRequest (err, request, reply) {
|
|
|
51
52
|
return
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
// Conditional assignment to avoid creating a new ContentType instance
|
|
56
|
+
// It can be assigned when accessing the .mediaType in hooks
|
|
57
|
+
if (!request[kRequestContentType]) {
|
|
58
|
+
request[kRequestContentType] = request[kRouteContext].contentTypeParser.getContentType(ctHeader)
|
|
59
|
+
}
|
|
60
|
+
if (request[kRequestContentType].isValid === false) {
|
|
56
61
|
reply[kReplyIsError] = true
|
|
57
62
|
reply.status(415).send(new FST_ERR_CTP_INVALID_MEDIA_TYPE())
|
|
58
63
|
return
|
|
59
64
|
}
|
|
60
|
-
request[kRouteContext].contentTypeParser.run(
|
|
65
|
+
request[kRouteContext].contentTypeParser.run(request[kRequestContentType].toString(), handler, request, reply)
|
|
61
66
|
return
|
|
62
67
|
}
|
|
63
68
|
|
|
@@ -142,6 +147,7 @@ function preHandlerCallback (err, request, reply) {
|
|
|
142
147
|
method: context.config.method
|
|
143
148
|
}
|
|
144
149
|
}
|
|
150
|
+
reply[kDiagnosticsStore] = store
|
|
145
151
|
channels.start.runStores(store, preHandlerCallbackInner, undefined, err, request, reply, store)
|
|
146
152
|
}
|
|
147
153
|
}
|
package/lib/plugin-override.js
CHANGED
|
@@ -82,7 +82,8 @@ function buildRoutePrefix (instancePrefix, pluginPrefix) {
|
|
|
82
82
|
if (instancePrefix.endsWith('/') && pluginPrefix[0] === '/') {
|
|
83
83
|
// Remove the extra '/' to avoid: '/first//second'
|
|
84
84
|
pluginPrefix = pluginPrefix.slice(1)
|
|
85
|
-
} else if (pluginPrefix[0] !== '/') {
|
|
85
|
+
} else if (pluginPrefix[0] !== '/' && !instancePrefix.endsWith('/')) {
|
|
86
|
+
// Add the missing '/' to avoid: '/firstsecond'
|
|
86
87
|
pluginPrefix = '/' + pluginPrefix
|
|
87
88
|
}
|
|
88
89
|
|
package/lib/plugin-utils.js
CHANGED
|
@@ -10,7 +10,8 @@ const { exist, existReply, existRequest } = require('./decorate.js')
|
|
|
10
10
|
const {
|
|
11
11
|
FST_ERR_PLUGIN_VERSION_MISMATCH,
|
|
12
12
|
FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE,
|
|
13
|
-
FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER
|
|
13
|
+
FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER,
|
|
14
|
+
FST_ERR_PLUGIN_DEPENDENCY_NOT_REGISTERED
|
|
14
15
|
} = require('./errors.js')
|
|
15
16
|
|
|
16
17
|
const rcRegex = /-(?:rc|pre|alpha).+$/u
|
|
@@ -70,10 +71,9 @@ function checkDependencies (fn) {
|
|
|
70
71
|
assert(Array.isArray(dependencies), 'The dependencies should be an array of strings')
|
|
71
72
|
|
|
72
73
|
dependencies.forEach(dependency => {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
)
|
|
74
|
+
if (!this[kRegisteredPlugins].includes(dependency)) {
|
|
75
|
+
throw new FST_ERR_PLUGIN_DEPENDENCY_NOT_REGISTERED(dependency, meta.name)
|
|
76
|
+
}
|
|
77
77
|
})
|
|
78
78
|
}
|
|
79
79
|
|