node-fastify 5.8.3
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/.borp.yaml +3 -0
- package/.markdownlint-cli2.yaml +22 -0
- package/.prettierignore +1 -0
- package/GOVERNANCE.md +4 -0
- package/LICENSE +21 -0
- package/PROJECT_CHARTER.md +126 -0
- package/README.md +423 -0
- package/SECURITY.md +220 -0
- package/SPONSORS.md +24 -0
- package/build/build-error-serializer.js +35 -0
- package/build/build-validation.js +169 -0
- package/build/sync-version.js +11 -0
- package/docs/Guides/Benchmarking.md +60 -0
- package/docs/Guides/Database.md +321 -0
- package/docs/Guides/Delay-Accepting-Requests.md +608 -0
- package/docs/Guides/Detecting-When-Clients-Abort.md +172 -0
- package/docs/Guides/Ecosystem.md +726 -0
- package/docs/Guides/Fluent-Schema.md +127 -0
- package/docs/Guides/Getting-Started.md +620 -0
- package/docs/Guides/Index.md +43 -0
- package/docs/Guides/Migration-Guide-V3.md +287 -0
- package/docs/Guides/Migration-Guide-V4.md +267 -0
- package/docs/Guides/Migration-Guide-V5.md +727 -0
- package/docs/Guides/Plugins-Guide.md +520 -0
- package/docs/Guides/Prototype-Poisoning.md +383 -0
- package/docs/Guides/Recommendations.md +378 -0
- package/docs/Guides/Serverless.md +604 -0
- package/docs/Guides/Style-Guide.md +246 -0
- package/docs/Guides/Testing.md +481 -0
- package/docs/Guides/Write-Plugin.md +103 -0
- package/docs/Guides/Write-Type-Provider.md +34 -0
- package/docs/Reference/ContentTypeParser.md +271 -0
- package/docs/Reference/Decorators.md +436 -0
- package/docs/Reference/Encapsulation.md +194 -0
- package/docs/Reference/Errors.md +377 -0
- package/docs/Reference/HTTP2.md +94 -0
- package/docs/Reference/Hooks.md +958 -0
- package/docs/Reference/Index.md +73 -0
- package/docs/Reference/LTS.md +86 -0
- package/docs/Reference/Lifecycle.md +99 -0
- package/docs/Reference/Logging.md +268 -0
- package/docs/Reference/Middleware.md +79 -0
- package/docs/Reference/Plugins.md +245 -0
- package/docs/Reference/Principles.md +73 -0
- package/docs/Reference/Reply.md +1001 -0
- package/docs/Reference/Request.md +295 -0
- package/docs/Reference/Routes.md +802 -0
- package/docs/Reference/Server.md +2389 -0
- package/docs/Reference/Type-Providers.md +256 -0
- package/docs/Reference/TypeScript.md +1729 -0
- package/docs/Reference/Validation-and-Serialization.md +1130 -0
- package/docs/Reference/Warnings.md +58 -0
- package/docs/index.md +24 -0
- package/docs/resources/encapsulation_context.drawio +1 -0
- package/docs/resources/encapsulation_context.svg +3 -0
- package/eslint.config.js +35 -0
- package/examples/asyncawait.js +38 -0
- package/examples/benchmark/body.json +3 -0
- package/examples/benchmark/hooks-benchmark-async-await.js +44 -0
- package/examples/benchmark/hooks-benchmark.js +52 -0
- package/examples/benchmark/parser.js +47 -0
- package/examples/benchmark/simple.js +30 -0
- package/examples/benchmark/webstream.js +27 -0
- package/examples/hooks.js +91 -0
- package/examples/http2.js +39 -0
- package/examples/https.js +38 -0
- package/examples/parser.js +53 -0
- package/examples/plugin.js +12 -0
- package/examples/route-prefix.js +38 -0
- package/examples/shared-schema.js +38 -0
- package/examples/simple-stream.js +20 -0
- package/examples/simple.js +32 -0
- package/examples/simple.mjs +27 -0
- package/examples/typescript-server.ts +79 -0
- package/examples/use-plugin.js +29 -0
- package/fastify.d.ts +253 -0
- package/fastify.js +985 -0
- package/integration/server.js +29 -0
- package/integration/test.sh +23 -0
- package/lib/config-validator.js +1266 -0
- package/lib/content-type-parser.js +413 -0
- package/lib/content-type.js +160 -0
- package/lib/context.js +98 -0
- package/lib/decorate.js +152 -0
- package/lib/error-handler.js +173 -0
- package/lib/error-serializer.js +134 -0
- package/lib/error-status.js +14 -0
- package/lib/errors.js +516 -0
- package/lib/four-oh-four.js +190 -0
- package/lib/handle-request.js +195 -0
- package/lib/head-route.js +45 -0
- package/lib/hooks.js +429 -0
- package/lib/initial-config-validation.js +37 -0
- package/lib/logger-factory.js +136 -0
- package/lib/logger-pino.js +68 -0
- package/lib/noop-set.js +10 -0
- package/lib/plugin-override.js +90 -0
- package/lib/plugin-utils.js +169 -0
- package/lib/promise.js +23 -0
- package/lib/reply.js +1030 -0
- package/lib/req-id-gen-factory.js +52 -0
- package/lib/request.js +391 -0
- package/lib/route.js +686 -0
- package/lib/schema-controller.js +164 -0
- package/lib/schemas.js +207 -0
- package/lib/server.js +441 -0
- package/lib/symbols.js +71 -0
- package/lib/validation.js +280 -0
- package/lib/warnings.js +57 -0
- package/lib/wrap-thenable.js +84 -0
- package/package.json +225 -0
- package/scripts/validate-ecosystem-links.js +179 -0
- package/test/404s.test.js +2035 -0
- package/test/500s.test.js +422 -0
- package/test/allow-unsafe-regex.test.js +92 -0
- package/test/als.test.js +65 -0
- package/test/async-await.test.js +705 -0
- package/test/async-dispose.test.js +20 -0
- package/test/async_hooks.test.js +52 -0
- package/test/body-limit.test.js +224 -0
- package/test/buffer.test.js +74 -0
- package/test/build/error-serializer.test.js +36 -0
- package/test/build/version.test.js +14 -0
- package/test/build-certificate.js +109 -0
- package/test/bundler/README.md +29 -0
- package/test/bundler/esbuild/bundler-test.js +32 -0
- package/test/bundler/esbuild/package.json +10 -0
- package/test/bundler/esbuild/src/fail-plugin-version.js +14 -0
- package/test/bundler/esbuild/src/index.js +9 -0
- package/test/bundler/webpack/bundler-test.js +32 -0
- package/test/bundler/webpack/package.json +11 -0
- package/test/bundler/webpack/src/fail-plugin-version.js +14 -0
- package/test/bundler/webpack/src/index.js +9 -0
- package/test/bundler/webpack/webpack.config.js +15 -0
- package/test/case-insensitive.test.js +102 -0
- package/test/chainable.test.js +40 -0
- package/test/child-logger-factory.test.js +128 -0
- package/test/client-timeout.test.js +38 -0
- package/test/close-pipelining.test.js +78 -0
- package/test/close.test.js +706 -0
- package/test/conditional-pino.test.js +47 -0
- package/test/connection-timeout.test.js +42 -0
- package/test/constrained-routes.test.js +1138 -0
- package/test/content-length.test.js +174 -0
- package/test/content-parser.test.js +739 -0
- package/test/content-type.test.js +181 -0
- package/test/context-config.test.js +164 -0
- package/test/custom-http-server.test.js +118 -0
- package/test/custom-parser-async.test.js +59 -0
- package/test/custom-parser.0.test.js +701 -0
- package/test/custom-parser.1.test.js +266 -0
- package/test/custom-parser.2.test.js +91 -0
- package/test/custom-parser.3.test.js +208 -0
- package/test/custom-parser.4.test.js +218 -0
- package/test/custom-parser.5.test.js +130 -0
- package/test/custom-querystring-parser.test.js +129 -0
- package/test/decorator.test.js +1330 -0
- package/test/delete.test.js +344 -0
- package/test/diagnostics-channel/404.test.js +49 -0
- package/test/diagnostics-channel/async-delay-request.test.js +65 -0
- package/test/diagnostics-channel/async-request.test.js +64 -0
- package/test/diagnostics-channel/error-before-handler.test.js +35 -0
- package/test/diagnostics-channel/error-request.test.js +53 -0
- package/test/diagnostics-channel/error-status.test.js +123 -0
- package/test/diagnostics-channel/init.test.js +50 -0
- package/test/diagnostics-channel/sync-delay-request.test.js +49 -0
- package/test/diagnostics-channel/sync-request-reply.test.js +51 -0
- package/test/diagnostics-channel/sync-request.test.js +54 -0
- package/test/encapsulated-child-logger-factory.test.js +69 -0
- package/test/encapsulated-error-handler.test.js +237 -0
- package/test/esm/errorCodes.test.mjs +10 -0
- package/test/esm/esm.test.mjs +13 -0
- package/test/esm/index.test.js +8 -0
- package/test/esm/named-exports.mjs +14 -0
- package/test/esm/other.mjs +8 -0
- package/test/esm/plugin.mjs +8 -0
- package/test/fastify-instance.test.js +300 -0
- package/test/find-route.test.js +152 -0
- package/test/fluent-schema.test.js +209 -0
- package/test/genReqId.test.js +426 -0
- package/test/handler-context.test.js +45 -0
- package/test/handler-timeout.test.js +367 -0
- package/test/has-route.test.js +88 -0
- package/test/header-overflow.test.js +55 -0
- package/test/helper.js +496 -0
- package/test/hooks-async.test.js +1099 -0
- package/test/hooks.on-listen.test.js +1162 -0
- package/test/hooks.on-ready.test.js +421 -0
- package/test/hooks.test.js +3578 -0
- package/test/http-methods/copy.test.js +35 -0
- package/test/http-methods/custom-http-methods.test.js +114 -0
- package/test/http-methods/get.test.js +412 -0
- package/test/http-methods/head.test.js +263 -0
- package/test/http-methods/lock.test.js +108 -0
- package/test/http-methods/mkcalendar.test.js +143 -0
- package/test/http-methods/mkcol.test.js +35 -0
- package/test/http-methods/move.test.js +42 -0
- package/test/http-methods/propfind.test.js +136 -0
- package/test/http-methods/proppatch.test.js +105 -0
- package/test/http-methods/report.test.js +142 -0
- package/test/http-methods/search.test.js +233 -0
- package/test/http-methods/trace.test.js +21 -0
- package/test/http-methods/unlock.test.js +38 -0
- package/test/http2/closing.test.js +270 -0
- package/test/http2/constraint.test.js +109 -0
- package/test/http2/head.test.js +34 -0
- package/test/http2/plain.test.js +68 -0
- package/test/http2/secure-with-fallback.test.js +113 -0
- package/test/http2/secure.test.js +67 -0
- package/test/http2/unknown-http-method.test.js +34 -0
- package/test/https/custom-https-server.test.js +58 -0
- package/test/https/https.test.js +136 -0
- package/test/imports.test.js +17 -0
- package/test/inject.test.js +502 -0
- package/test/input-validation.js +335 -0
- package/test/internals/all.test.js +38 -0
- package/test/internals/content-type-parser.test.js +111 -0
- package/test/internals/context.test.js +31 -0
- package/test/internals/decorator.test.js +156 -0
- package/test/internals/errors.test.js +982 -0
- package/test/internals/handle-request.test.js +270 -0
- package/test/internals/hook-runner.test.js +449 -0
- package/test/internals/hooks.test.js +96 -0
- package/test/internals/initial-config.test.js +383 -0
- package/test/internals/logger.test.js +163 -0
- package/test/internals/plugin.test.js +170 -0
- package/test/internals/promise.test.js +63 -0
- package/test/internals/reply-serialize.test.js +714 -0
- package/test/internals/reply.test.js +1920 -0
- package/test/internals/req-id-gen-factory.test.js +133 -0
- package/test/internals/request-validate.test.js +1402 -0
- package/test/internals/request.test.js +506 -0
- package/test/internals/schema-controller-perf.test.js +40 -0
- package/test/internals/server.test.js +91 -0
- package/test/internals/validation.test.js +352 -0
- package/test/issue-4959.test.js +118 -0
- package/test/keep-alive-timeout.test.js +42 -0
- package/test/listen.1.test.js +154 -0
- package/test/listen.2.test.js +113 -0
- package/test/listen.3.test.js +83 -0
- package/test/listen.4.test.js +168 -0
- package/test/listen.5.test.js +122 -0
- package/test/logger/instantiation.test.js +341 -0
- package/test/logger/logger-test-utils.js +47 -0
- package/test/logger/logging.test.js +460 -0
- package/test/logger/options.test.js +579 -0
- package/test/logger/request.test.js +292 -0
- package/test/logger/response.test.js +183 -0
- package/test/logger/tap-parallel-not-ok +0 -0
- package/test/max-requests-per-socket.test.js +113 -0
- package/test/middleware.test.js +37 -0
- package/test/noop-set.test.js +19 -0
- package/test/nullable-validation.test.js +187 -0
- package/test/options.error-handler.test.js +5 -0
- package/test/options.test.js +5 -0
- package/test/output-validation.test.js +140 -0
- package/test/patch.error-handler.test.js +5 -0
- package/test/patch.test.js +5 -0
- package/test/plugin.1.test.js +230 -0
- package/test/plugin.2.test.js +314 -0
- package/test/plugin.3.test.js +287 -0
- package/test/plugin.4.test.js +504 -0
- package/test/plugin.helper.js +8 -0
- package/test/plugin.name.display.js +10 -0
- package/test/post-empty-body.test.js +38 -0
- package/test/pretty-print.test.js +366 -0
- package/test/promises.test.js +125 -0
- package/test/proto-poisoning.test.js +145 -0
- package/test/put.error-handler.test.js +5 -0
- package/test/put.test.js +5 -0
- package/test/register.test.js +184 -0
- package/test/reply-code.test.js +148 -0
- package/test/reply-early-hints.test.js +100 -0
- package/test/reply-error.test.js +815 -0
- package/test/reply-trailers.test.js +445 -0
- package/test/reply-web-stream-locked.test.js +37 -0
- package/test/request-error.test.js +624 -0
- package/test/request-header-host.test.js +339 -0
- package/test/request-id.test.js +118 -0
- package/test/request-timeout.test.js +53 -0
- package/test/route-hooks.test.js +635 -0
- package/test/route-prefix.test.js +904 -0
- package/test/route-shorthand.test.js +48 -0
- package/test/route.1.test.js +259 -0
- package/test/route.2.test.js +100 -0
- package/test/route.3.test.js +213 -0
- package/test/route.4.test.js +127 -0
- package/test/route.5.test.js +211 -0
- package/test/route.6.test.js +306 -0
- package/test/route.7.test.js +406 -0
- package/test/route.8.test.js +225 -0
- package/test/router-options.test.js +1108 -0
- package/test/same-shape.test.js +124 -0
- package/test/schema-examples.test.js +661 -0
- package/test/schema-feature.test.js +2198 -0
- package/test/schema-serialization.test.js +1171 -0
- package/test/schema-special-usage.test.js +1348 -0
- package/test/schema-validation.test.js +1572 -0
- package/test/scripts/validate-ecosystem-links.test.js +339 -0
- package/test/serialize-response.test.js +186 -0
- package/test/server.test.js +347 -0
- package/test/set-error-handler.test.js +69 -0
- package/test/skip-reply-send.test.js +317 -0
- package/test/stream-serializers.test.js +40 -0
- package/test/stream.1.test.js +94 -0
- package/test/stream.2.test.js +129 -0
- package/test/stream.3.test.js +198 -0
- package/test/stream.4.test.js +176 -0
- package/test/stream.5.test.js +188 -0
- package/test/sync-routes.test.js +32 -0
- package/test/throw.test.js +359 -0
- package/test/toolkit.js +63 -0
- package/test/trust-proxy.test.js +162 -0
- package/test/type-provider.test.js +22 -0
- package/test/types/content-type-parser.test-d.ts +72 -0
- package/test/types/decorate-request-reply.test-d.ts +18 -0
- package/test/types/dummy-plugin.ts +9 -0
- package/test/types/errors.test-d.ts +90 -0
- package/test/types/fastify.test-d.ts +352 -0
- package/test/types/hooks.test-d.ts +550 -0
- package/test/types/import.ts +2 -0
- package/test/types/instance.test-d.ts +588 -0
- package/test/types/logger.test-d.ts +277 -0
- package/test/types/plugin.test-d.ts +97 -0
- package/test/types/register.test-d.ts +237 -0
- package/test/types/reply.test-d.ts +254 -0
- package/test/types/request.test-d.ts +188 -0
- package/test/types/route.test-d.ts +553 -0
- package/test/types/schema.test-d.ts +135 -0
- package/test/types/serverFactory.test-d.ts +37 -0
- package/test/types/type-provider.test-d.ts +1213 -0
- package/test/types/using.test-d.ts +17 -0
- package/test/upgrade.test.js +52 -0
- package/test/url-rewriting.test.js +122 -0
- package/test/use-semicolon-delimiter.test.js +168 -0
- package/test/validation-error-handling.test.js +900 -0
- package/test/versioned-routes.test.js +603 -0
- package/test/web-api.test.js +616 -0
- package/test/wrap-thenable.test.js +30 -0
- package/types/content-type-parser.d.ts +75 -0
- package/types/context.d.ts +22 -0
- package/types/errors.d.ts +92 -0
- package/types/hooks.d.ts +875 -0
- package/types/instance.d.ts +609 -0
- package/types/logger.d.ts +107 -0
- package/types/plugin.d.ts +44 -0
- package/types/register.d.ts +42 -0
- package/types/reply.d.ts +81 -0
- package/types/request.d.ts +95 -0
- package/types/route.d.ts +199 -0
- package/types/schema.d.ts +61 -0
- package/types/server-factory.d.ts +19 -0
- package/types/type-provider.d.ts +130 -0
- package/types/utils.d.ts +98 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED,
|
|
5
|
+
FST_ERR_LOG_INVALID_LOGGER_CONFIG,
|
|
6
|
+
FST_ERR_LOG_INVALID_LOGGER_INSTANCE,
|
|
7
|
+
FST_ERR_LOG_INVALID_LOGGER
|
|
8
|
+
} = require('./errors')
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Utility for creating a child logger with the appropriate bindings, logger factory
|
|
12
|
+
* and validation.
|
|
13
|
+
* @param {object} context
|
|
14
|
+
* @param {import('../fastify').FastifyBaseLogger} logger
|
|
15
|
+
* @param {import('../fastify').RawRequestDefaultExpression<any>} req
|
|
16
|
+
* @param {string} reqId
|
|
17
|
+
* @param {import('../types/logger.js').ChildLoggerOptions?} loggerOpts
|
|
18
|
+
*
|
|
19
|
+
* @returns {object} New logger instance, inheriting all parent bindings,
|
|
20
|
+
* with child bindings added.
|
|
21
|
+
*/
|
|
22
|
+
function createChildLogger (context, logger, req, reqId, loggerOpts) {
|
|
23
|
+
const loggerBindings = {
|
|
24
|
+
[context.requestIdLogLabel]: reqId
|
|
25
|
+
}
|
|
26
|
+
const child = context.childLoggerFactory.call(context.server, logger, loggerBindings, loggerOpts || {}, req)
|
|
27
|
+
|
|
28
|
+
// Optimization: bypass validation if the factory is our own default factory
|
|
29
|
+
if (context.childLoggerFactory !== defaultChildLoggerFactory) {
|
|
30
|
+
validateLogger(child, true) // throw if the child is not a valid logger
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return child
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Default factory to create child logger instance
|
|
37
|
+
*
|
|
38
|
+
* @param {import('../fastify.js').FastifyBaseLogger} logger
|
|
39
|
+
* @param {import('../types/logger.js').Bindings} bindings
|
|
40
|
+
* @param {import('../types/logger.js').ChildLoggerOptions} opts
|
|
41
|
+
*
|
|
42
|
+
* @returns {import('../types/logger.js').FastifyBaseLogger}
|
|
43
|
+
*/
|
|
44
|
+
function defaultChildLoggerFactory (logger, bindings, opts) {
|
|
45
|
+
return logger.child(bindings, opts)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Determines if a provided logger object meets the requirements
|
|
50
|
+
* of a Fastify compatible logger.
|
|
51
|
+
*
|
|
52
|
+
* @param {object} logger Object to validate.
|
|
53
|
+
* @param {boolean?} strict `true` if the object must be a logger (always throw if any methods missing)
|
|
54
|
+
*
|
|
55
|
+
* @returns {boolean} `true` when the logger meets the requirements.
|
|
56
|
+
*
|
|
57
|
+
* @throws {FST_ERR_LOG_INVALID_LOGGER} When the logger object is
|
|
58
|
+
* missing required methods.
|
|
59
|
+
*/
|
|
60
|
+
function validateLogger (logger, strict) {
|
|
61
|
+
const methods = ['info', 'error', 'debug', 'fatal', 'warn', 'trace', 'child']
|
|
62
|
+
const missingMethods = logger
|
|
63
|
+
? methods.filter(method => !logger[method] || typeof logger[method] !== 'function')
|
|
64
|
+
: methods
|
|
65
|
+
|
|
66
|
+
if (!missingMethods.length) {
|
|
67
|
+
return true
|
|
68
|
+
} else if ((missingMethods.length === methods.length) && !strict) {
|
|
69
|
+
return false
|
|
70
|
+
} else {
|
|
71
|
+
throw FST_ERR_LOG_INVALID_LOGGER(missingMethods.join(','))
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function createLogger (options) {
|
|
76
|
+
if (options.logger && options.loggerInstance) {
|
|
77
|
+
throw new FST_ERR_LOG_LOGGER_AND_LOGGER_INSTANCE_PROVIDED()
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!options.loggerInstance && !options.logger) {
|
|
81
|
+
const nullLogger = require('abstract-logging')
|
|
82
|
+
const logger = nullLogger
|
|
83
|
+
logger.child = () => logger
|
|
84
|
+
return { logger, hasLogger: false }
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const { createPinoLogger, serializers } = require('./logger-pino.js')
|
|
88
|
+
|
|
89
|
+
// check if the logger instance has all required properties
|
|
90
|
+
if (validateLogger(options.loggerInstance)) {
|
|
91
|
+
const logger = createPinoLogger({
|
|
92
|
+
logger: options.loggerInstance,
|
|
93
|
+
serializers: Object.assign({}, serializers, options.loggerInstance.serializers)
|
|
94
|
+
})
|
|
95
|
+
return { logger, hasLogger: true }
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// if a logger instance is passed to logger, throw an exception
|
|
99
|
+
if (validateLogger(options.logger)) {
|
|
100
|
+
throw FST_ERR_LOG_INVALID_LOGGER_CONFIG()
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (options.loggerInstance) {
|
|
104
|
+
throw FST_ERR_LOG_INVALID_LOGGER_INSTANCE()
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const localLoggerOptions = {}
|
|
108
|
+
if (Object.prototype.toString.call(options.logger) === '[object Object]') {
|
|
109
|
+
Reflect.ownKeys(options.logger).forEach(prop => {
|
|
110
|
+
Object.defineProperty(localLoggerOptions, prop, {
|
|
111
|
+
value: options.logger[prop],
|
|
112
|
+
writable: true,
|
|
113
|
+
enumerable: true,
|
|
114
|
+
configurable: true
|
|
115
|
+
})
|
|
116
|
+
})
|
|
117
|
+
}
|
|
118
|
+
localLoggerOptions.level = localLoggerOptions.level || 'info'
|
|
119
|
+
localLoggerOptions.serializers = Object.assign({}, serializers, localLoggerOptions.serializers)
|
|
120
|
+
options.logger = localLoggerOptions
|
|
121
|
+
const logger = createPinoLogger(options.logger)
|
|
122
|
+
return { logger, hasLogger: true }
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function now () {
|
|
126
|
+
const ts = process.hrtime()
|
|
127
|
+
return (ts[0] * 1e3) + (ts[1] / 1e6)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
module.exports = {
|
|
131
|
+
createChildLogger,
|
|
132
|
+
defaultChildLoggerFactory,
|
|
133
|
+
createLogger,
|
|
134
|
+
validateLogger,
|
|
135
|
+
now
|
|
136
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Code imported from `pino-http`
|
|
5
|
+
* Repo: https://github.com/pinojs/pino-http
|
|
6
|
+
* License: MIT (https://raw.githubusercontent.com/pinojs/pino-http/master/LICENSE)
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const pino = require('pino')
|
|
10
|
+
const { serializersSym } = pino.symbols
|
|
11
|
+
const {
|
|
12
|
+
FST_ERR_LOG_INVALID_DESTINATION
|
|
13
|
+
} = require('./errors')
|
|
14
|
+
|
|
15
|
+
function createPinoLogger (opts) {
|
|
16
|
+
if (opts.stream && opts.file) {
|
|
17
|
+
throw new FST_ERR_LOG_INVALID_DESTINATION()
|
|
18
|
+
} else if (opts.file) {
|
|
19
|
+
// we do not have stream
|
|
20
|
+
opts.stream = pino.destination(opts.file)
|
|
21
|
+
delete opts.file
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const prevLogger = opts.logger
|
|
25
|
+
const prevGenReqId = opts.genReqId
|
|
26
|
+
let logger = null
|
|
27
|
+
|
|
28
|
+
if (prevLogger) {
|
|
29
|
+
opts.logger = undefined
|
|
30
|
+
opts.genReqId = undefined
|
|
31
|
+
// we need to tap into pino internals because in v5 it supports
|
|
32
|
+
// adding serializers in child loggers
|
|
33
|
+
if (prevLogger[serializersSym]) {
|
|
34
|
+
opts.serializers = Object.assign({}, opts.serializers, prevLogger[serializersSym])
|
|
35
|
+
}
|
|
36
|
+
logger = prevLogger.child({}, opts)
|
|
37
|
+
opts.logger = prevLogger
|
|
38
|
+
opts.genReqId = prevGenReqId
|
|
39
|
+
} else {
|
|
40
|
+
logger = pino(opts, opts.stream)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return logger
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const serializers = {
|
|
47
|
+
req: function asReqValue (req) {
|
|
48
|
+
return {
|
|
49
|
+
method: req.method,
|
|
50
|
+
url: req.url,
|
|
51
|
+
version: req.headers && req.headers['accept-version'],
|
|
52
|
+
host: req.host,
|
|
53
|
+
remoteAddress: req.ip,
|
|
54
|
+
remotePort: req.socket ? req.socket.remotePort : undefined
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
err: pino.stdSerializers.err,
|
|
58
|
+
res: function asResValue (reply) {
|
|
59
|
+
return {
|
|
60
|
+
statusCode: reply.statusCode
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
module.exports = {
|
|
66
|
+
serializers,
|
|
67
|
+
createPinoLogger
|
|
68
|
+
}
|
package/lib/noop-set.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
kAvvioBoot,
|
|
5
|
+
kChildren,
|
|
6
|
+
kRoutePrefix,
|
|
7
|
+
kLogLevel,
|
|
8
|
+
kLogSerializers,
|
|
9
|
+
kHooks,
|
|
10
|
+
kSchemaController,
|
|
11
|
+
kContentTypeParser,
|
|
12
|
+
kReply,
|
|
13
|
+
kRequest,
|
|
14
|
+
kFourOhFour,
|
|
15
|
+
kPluginNameChain,
|
|
16
|
+
kErrorHandlerAlreadySet
|
|
17
|
+
} = require('./symbols.js')
|
|
18
|
+
|
|
19
|
+
const Reply = require('./reply')
|
|
20
|
+
const Request = require('./request')
|
|
21
|
+
const SchemaController = require('./schema-controller')
|
|
22
|
+
const ContentTypeParser = require('./content-type-parser.js')
|
|
23
|
+
const { buildHooks } = require('./hooks')
|
|
24
|
+
const pluginUtils = require('./plugin-utils.js')
|
|
25
|
+
|
|
26
|
+
// Function that runs the encapsulation magic.
|
|
27
|
+
// Everything that need to be encapsulated must be handled in this function.
|
|
28
|
+
module.exports = function override (old, fn, opts) {
|
|
29
|
+
const shouldSkipOverride = pluginUtils.registerPlugin.call(old, fn)
|
|
30
|
+
|
|
31
|
+
const fnName = pluginUtils.getPluginName(fn) || pluginUtils.getFuncPreview(fn)
|
|
32
|
+
if (shouldSkipOverride) {
|
|
33
|
+
// after every plugin registration we will enter a new name
|
|
34
|
+
old[kPluginNameChain].push(fnName)
|
|
35
|
+
return old
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const instance = Object.create(old)
|
|
39
|
+
old[kChildren].push(instance)
|
|
40
|
+
instance.ready = old[kAvvioBoot].bind(instance)
|
|
41
|
+
instance[kChildren] = []
|
|
42
|
+
|
|
43
|
+
instance[kReply] = Reply.buildReply(instance[kReply])
|
|
44
|
+
instance[kRequest] = Request.buildRequest(instance[kRequest])
|
|
45
|
+
|
|
46
|
+
instance[kContentTypeParser] = ContentTypeParser.helpers.buildContentTypeParser(instance[kContentTypeParser])
|
|
47
|
+
instance[kHooks] = buildHooks(instance[kHooks])
|
|
48
|
+
instance[kRoutePrefix] = buildRoutePrefix(instance[kRoutePrefix], opts.prefix)
|
|
49
|
+
instance[kLogLevel] = opts.logLevel || instance[kLogLevel]
|
|
50
|
+
instance[kSchemaController] = SchemaController.buildSchemaController(old[kSchemaController])
|
|
51
|
+
instance.getSchema = instance[kSchemaController].getSchema.bind(instance[kSchemaController])
|
|
52
|
+
instance.getSchemas = instance[kSchemaController].getSchemas.bind(instance[kSchemaController])
|
|
53
|
+
|
|
54
|
+
// Track the registered and loaded plugins since the root instance.
|
|
55
|
+
// It does not track the current encapsulated plugin.
|
|
56
|
+
instance[pluginUtils.kRegisteredPlugins] = Object.create(instance[pluginUtils.kRegisteredPlugins])
|
|
57
|
+
|
|
58
|
+
// Track the plugin chain since the root instance.
|
|
59
|
+
// When an non-encapsulated plugin is added, the chain will be updated.
|
|
60
|
+
instance[kPluginNameChain] = [fnName]
|
|
61
|
+
instance[kErrorHandlerAlreadySet] = false
|
|
62
|
+
|
|
63
|
+
if (instance[kLogSerializers] || opts.logSerializers) {
|
|
64
|
+
instance[kLogSerializers] = Object.assign(Object.create(instance[kLogSerializers]), opts.logSerializers)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (opts.prefix) {
|
|
68
|
+
instance[kFourOhFour].arrange404(instance)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
for (const hook of instance[kHooks].onRegister) hook.call(old, instance, opts)
|
|
72
|
+
|
|
73
|
+
return instance
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function buildRoutePrefix (instancePrefix, pluginPrefix) {
|
|
77
|
+
if (!pluginPrefix) {
|
|
78
|
+
return instancePrefix
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Ensure that there is a '/' between the prefixes
|
|
82
|
+
if (instancePrefix.endsWith('/') && pluginPrefix[0] === '/') {
|
|
83
|
+
// Remove the extra '/' to avoid: '/first//second'
|
|
84
|
+
pluginPrefix = pluginPrefix.slice(1)
|
|
85
|
+
} else if (pluginPrefix[0] !== '/') {
|
|
86
|
+
pluginPrefix = '/' + pluginPrefix
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return instancePrefix + pluginPrefix
|
|
90
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const semver = require('semver')
|
|
4
|
+
const assert = require('node:assert')
|
|
5
|
+
const kRegisteredPlugins = Symbol.for('registered-plugin')
|
|
6
|
+
const {
|
|
7
|
+
kTestInternals
|
|
8
|
+
} = require('./symbols.js')
|
|
9
|
+
const { exist, existReply, existRequest } = require('./decorate.js')
|
|
10
|
+
const {
|
|
11
|
+
FST_ERR_PLUGIN_VERSION_MISMATCH,
|
|
12
|
+
FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE,
|
|
13
|
+
FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER
|
|
14
|
+
} = require('./errors.js')
|
|
15
|
+
|
|
16
|
+
const rcRegex = /-(?:rc|pre|alpha).+$/u
|
|
17
|
+
|
|
18
|
+
function getMeta (fn) {
|
|
19
|
+
return fn[Symbol.for('plugin-meta')]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function getPluginName (func) {
|
|
23
|
+
const display = getDisplayName(func)
|
|
24
|
+
if (display) {
|
|
25
|
+
return display
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// let's see if this is a file, and in that case use that
|
|
29
|
+
// this is common for plugins
|
|
30
|
+
const cache = require.cache
|
|
31
|
+
// cache is undefined inside SEA
|
|
32
|
+
if (cache) {
|
|
33
|
+
const keys = Object.keys(cache)
|
|
34
|
+
|
|
35
|
+
for (let i = 0; i < keys.length; i++) {
|
|
36
|
+
const key = keys[i]
|
|
37
|
+
if (cache[key].exports === func) {
|
|
38
|
+
return key
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// if not maybe it's a named function, so use that
|
|
44
|
+
if (func.name) {
|
|
45
|
+
return func.name
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return null
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getFuncPreview (func) {
|
|
52
|
+
// takes the first two lines of the function if nothing else works
|
|
53
|
+
return func.toString().split('\n', 2).map(s => s.trim()).join(' -- ')
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getDisplayName (fn) {
|
|
57
|
+
return fn[Symbol.for('fastify.display-name')]
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function shouldSkipOverride (fn) {
|
|
61
|
+
return !!fn[Symbol.for('skip-override')]
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function checkDependencies (fn) {
|
|
65
|
+
const meta = getMeta(fn)
|
|
66
|
+
if (!meta) return
|
|
67
|
+
|
|
68
|
+
const dependencies = meta.dependencies
|
|
69
|
+
if (!dependencies) return
|
|
70
|
+
assert(Array.isArray(dependencies), 'The dependencies should be an array of strings')
|
|
71
|
+
|
|
72
|
+
dependencies.forEach(dependency => {
|
|
73
|
+
assert(
|
|
74
|
+
this[kRegisteredPlugins].indexOf(dependency) > -1,
|
|
75
|
+
`The dependency '${dependency}' of plugin '${meta.name}' is not registered`
|
|
76
|
+
)
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function checkDecorators (fn) {
|
|
81
|
+
const meta = getMeta(fn)
|
|
82
|
+
if (!meta) return
|
|
83
|
+
|
|
84
|
+
const { decorators, name } = meta
|
|
85
|
+
if (!decorators) return
|
|
86
|
+
|
|
87
|
+
if (decorators.fastify) _checkDecorators(this, 'Fastify', decorators.fastify, name)
|
|
88
|
+
if (decorators.reply) _checkDecorators(this, 'Reply', decorators.reply, name)
|
|
89
|
+
if (decorators.request) _checkDecorators(this, 'Request', decorators.request, name)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const checks = {
|
|
93
|
+
Fastify: exist,
|
|
94
|
+
Request: existRequest,
|
|
95
|
+
Reply: existReply
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function _checkDecorators (that, instance, decorators, name) {
|
|
99
|
+
assert(Array.isArray(decorators), 'The decorators should be an array of strings')
|
|
100
|
+
|
|
101
|
+
decorators.forEach(decorator => {
|
|
102
|
+
const withPluginName = typeof name === 'string' ? ` required by '${name}'` : ''
|
|
103
|
+
if (!checks[instance].call(that, decorator)) {
|
|
104
|
+
throw new FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE(decorator, withPluginName, instance)
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function checkVersion (fn) {
|
|
110
|
+
const meta = getMeta(fn)
|
|
111
|
+
if (meta?.fastify == null) return
|
|
112
|
+
|
|
113
|
+
const requiredVersion = meta.fastify
|
|
114
|
+
|
|
115
|
+
const fastifyRc = rcRegex.test(this.version)
|
|
116
|
+
if (fastifyRc === true && semver.gt(this.version, semver.coerce(requiredVersion)) === true) {
|
|
117
|
+
// A Fastify release candidate phase is taking place. In order to reduce
|
|
118
|
+
// the effort needed to test plugins with the RC, we allow plugins targeting
|
|
119
|
+
// the prior Fastify release to be loaded.
|
|
120
|
+
return
|
|
121
|
+
}
|
|
122
|
+
if (requiredVersion && semver.satisfies(this.version, requiredVersion, { includePrerelease: fastifyRc }) === false) {
|
|
123
|
+
// We are not in a release candidate phase. Thus, we must honor the semver
|
|
124
|
+
// ranges defined by the plugin's metadata. Which is to say, if the plugin
|
|
125
|
+
// expects an older version of Fastify than the _current_ version, we will
|
|
126
|
+
// throw an error.
|
|
127
|
+
throw new FST_ERR_PLUGIN_VERSION_MISMATCH(meta.name, requiredVersion, this.version)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function registerPluginName (fn) {
|
|
132
|
+
const meta = getMeta(fn)
|
|
133
|
+
if (!meta) return
|
|
134
|
+
|
|
135
|
+
const name = meta.name
|
|
136
|
+
if (!name) return
|
|
137
|
+
this[kRegisteredPlugins].push(name)
|
|
138
|
+
return name
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function checkPluginHealthiness (fn, pluginName) {
|
|
142
|
+
if (fn.constructor.name === 'AsyncFunction' && fn.length === 3) {
|
|
143
|
+
throw new FST_ERR_PLUGIN_INVALID_ASYNC_HANDLER(pluginName)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function registerPlugin (fn) {
|
|
148
|
+
const pluginName = registerPluginName.call(this, fn) || getPluginName(fn)
|
|
149
|
+
checkPluginHealthiness.call(this, fn, pluginName)
|
|
150
|
+
checkVersion.call(this, fn)
|
|
151
|
+
checkDecorators.call(this, fn)
|
|
152
|
+
checkDependencies.call(this, fn)
|
|
153
|
+
return shouldSkipOverride(fn)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
module.exports = {
|
|
157
|
+
getPluginName,
|
|
158
|
+
getFuncPreview,
|
|
159
|
+
kRegisteredPlugins,
|
|
160
|
+
getDisplayName,
|
|
161
|
+
registerPlugin
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
module.exports[kTestInternals] = {
|
|
165
|
+
shouldSkipOverride,
|
|
166
|
+
getMeta,
|
|
167
|
+
checkDecorators,
|
|
168
|
+
checkDependencies
|
|
169
|
+
}
|
package/lib/promise.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { kTestInternals } = require('./symbols')
|
|
4
|
+
|
|
5
|
+
function withResolvers () {
|
|
6
|
+
let res, rej
|
|
7
|
+
const promise = new Promise((resolve, reject) => {
|
|
8
|
+
res = resolve
|
|
9
|
+
rej = reject
|
|
10
|
+
})
|
|
11
|
+
return { promise, resolve: res, reject: rej }
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
module.exports = {
|
|
15
|
+
// TODO(20.x): remove when node@20 is not supported
|
|
16
|
+
withResolvers: typeof Promise.withResolvers === 'function'
|
|
17
|
+
? Promise.withResolvers.bind(Promise) // Promise.withResolvers must bind to itself
|
|
18
|
+
/* c8 ignore next */
|
|
19
|
+
: withResolvers, // Tested using the kTestInternals
|
|
20
|
+
[kTestInternals]: {
|
|
21
|
+
withResolvers
|
|
22
|
+
}
|
|
23
|
+
}
|