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.
Files changed (354) hide show
  1. package/.borp.yaml +3 -0
  2. package/.markdownlint-cli2.yaml +22 -0
  3. package/.prettierignore +1 -0
  4. package/GOVERNANCE.md +4 -0
  5. package/LICENSE +21 -0
  6. package/PROJECT_CHARTER.md +126 -0
  7. package/README.md +423 -0
  8. package/SECURITY.md +220 -0
  9. package/SPONSORS.md +24 -0
  10. package/build/build-error-serializer.js +35 -0
  11. package/build/build-validation.js +169 -0
  12. package/build/sync-version.js +11 -0
  13. package/docs/Guides/Benchmarking.md +60 -0
  14. package/docs/Guides/Database.md +321 -0
  15. package/docs/Guides/Delay-Accepting-Requests.md +608 -0
  16. package/docs/Guides/Detecting-When-Clients-Abort.md +172 -0
  17. package/docs/Guides/Ecosystem.md +726 -0
  18. package/docs/Guides/Fluent-Schema.md +127 -0
  19. package/docs/Guides/Getting-Started.md +620 -0
  20. package/docs/Guides/Index.md +43 -0
  21. package/docs/Guides/Migration-Guide-V3.md +287 -0
  22. package/docs/Guides/Migration-Guide-V4.md +267 -0
  23. package/docs/Guides/Migration-Guide-V5.md +727 -0
  24. package/docs/Guides/Plugins-Guide.md +520 -0
  25. package/docs/Guides/Prototype-Poisoning.md +383 -0
  26. package/docs/Guides/Recommendations.md +378 -0
  27. package/docs/Guides/Serverless.md +604 -0
  28. package/docs/Guides/Style-Guide.md +246 -0
  29. package/docs/Guides/Testing.md +481 -0
  30. package/docs/Guides/Write-Plugin.md +103 -0
  31. package/docs/Guides/Write-Type-Provider.md +34 -0
  32. package/docs/Reference/ContentTypeParser.md +271 -0
  33. package/docs/Reference/Decorators.md +436 -0
  34. package/docs/Reference/Encapsulation.md +194 -0
  35. package/docs/Reference/Errors.md +377 -0
  36. package/docs/Reference/HTTP2.md +94 -0
  37. package/docs/Reference/Hooks.md +958 -0
  38. package/docs/Reference/Index.md +73 -0
  39. package/docs/Reference/LTS.md +86 -0
  40. package/docs/Reference/Lifecycle.md +99 -0
  41. package/docs/Reference/Logging.md +268 -0
  42. package/docs/Reference/Middleware.md +79 -0
  43. package/docs/Reference/Plugins.md +245 -0
  44. package/docs/Reference/Principles.md +73 -0
  45. package/docs/Reference/Reply.md +1001 -0
  46. package/docs/Reference/Request.md +295 -0
  47. package/docs/Reference/Routes.md +802 -0
  48. package/docs/Reference/Server.md +2389 -0
  49. package/docs/Reference/Type-Providers.md +256 -0
  50. package/docs/Reference/TypeScript.md +1729 -0
  51. package/docs/Reference/Validation-and-Serialization.md +1130 -0
  52. package/docs/Reference/Warnings.md +58 -0
  53. package/docs/index.md +24 -0
  54. package/docs/resources/encapsulation_context.drawio +1 -0
  55. package/docs/resources/encapsulation_context.svg +3 -0
  56. package/eslint.config.js +35 -0
  57. package/examples/asyncawait.js +38 -0
  58. package/examples/benchmark/body.json +3 -0
  59. package/examples/benchmark/hooks-benchmark-async-await.js +44 -0
  60. package/examples/benchmark/hooks-benchmark.js +52 -0
  61. package/examples/benchmark/parser.js +47 -0
  62. package/examples/benchmark/simple.js +30 -0
  63. package/examples/benchmark/webstream.js +27 -0
  64. package/examples/hooks.js +91 -0
  65. package/examples/http2.js +39 -0
  66. package/examples/https.js +38 -0
  67. package/examples/parser.js +53 -0
  68. package/examples/plugin.js +12 -0
  69. package/examples/route-prefix.js +38 -0
  70. package/examples/shared-schema.js +38 -0
  71. package/examples/simple-stream.js +20 -0
  72. package/examples/simple.js +32 -0
  73. package/examples/simple.mjs +27 -0
  74. package/examples/typescript-server.ts +79 -0
  75. package/examples/use-plugin.js +29 -0
  76. package/fastify.d.ts +253 -0
  77. package/fastify.js +985 -0
  78. package/integration/server.js +29 -0
  79. package/integration/test.sh +23 -0
  80. package/lib/config-validator.js +1266 -0
  81. package/lib/content-type-parser.js +413 -0
  82. package/lib/content-type.js +160 -0
  83. package/lib/context.js +98 -0
  84. package/lib/decorate.js +152 -0
  85. package/lib/error-handler.js +173 -0
  86. package/lib/error-serializer.js +134 -0
  87. package/lib/error-status.js +14 -0
  88. package/lib/errors.js +516 -0
  89. package/lib/four-oh-four.js +190 -0
  90. package/lib/handle-request.js +195 -0
  91. package/lib/head-route.js +45 -0
  92. package/lib/hooks.js +429 -0
  93. package/lib/initial-config-validation.js +37 -0
  94. package/lib/logger-factory.js +136 -0
  95. package/lib/logger-pino.js +68 -0
  96. package/lib/noop-set.js +10 -0
  97. package/lib/plugin-override.js +90 -0
  98. package/lib/plugin-utils.js +169 -0
  99. package/lib/promise.js +23 -0
  100. package/lib/reply.js +1030 -0
  101. package/lib/req-id-gen-factory.js +52 -0
  102. package/lib/request.js +391 -0
  103. package/lib/route.js +686 -0
  104. package/lib/schema-controller.js +164 -0
  105. package/lib/schemas.js +207 -0
  106. package/lib/server.js +441 -0
  107. package/lib/symbols.js +71 -0
  108. package/lib/validation.js +280 -0
  109. package/lib/warnings.js +57 -0
  110. package/lib/wrap-thenable.js +84 -0
  111. package/package.json +225 -0
  112. package/scripts/validate-ecosystem-links.js +179 -0
  113. package/test/404s.test.js +2035 -0
  114. package/test/500s.test.js +422 -0
  115. package/test/allow-unsafe-regex.test.js +92 -0
  116. package/test/als.test.js +65 -0
  117. package/test/async-await.test.js +705 -0
  118. package/test/async-dispose.test.js +20 -0
  119. package/test/async_hooks.test.js +52 -0
  120. package/test/body-limit.test.js +224 -0
  121. package/test/buffer.test.js +74 -0
  122. package/test/build/error-serializer.test.js +36 -0
  123. package/test/build/version.test.js +14 -0
  124. package/test/build-certificate.js +109 -0
  125. package/test/bundler/README.md +29 -0
  126. package/test/bundler/esbuild/bundler-test.js +32 -0
  127. package/test/bundler/esbuild/package.json +10 -0
  128. package/test/bundler/esbuild/src/fail-plugin-version.js +14 -0
  129. package/test/bundler/esbuild/src/index.js +9 -0
  130. package/test/bundler/webpack/bundler-test.js +32 -0
  131. package/test/bundler/webpack/package.json +11 -0
  132. package/test/bundler/webpack/src/fail-plugin-version.js +14 -0
  133. package/test/bundler/webpack/src/index.js +9 -0
  134. package/test/bundler/webpack/webpack.config.js +15 -0
  135. package/test/case-insensitive.test.js +102 -0
  136. package/test/chainable.test.js +40 -0
  137. package/test/child-logger-factory.test.js +128 -0
  138. package/test/client-timeout.test.js +38 -0
  139. package/test/close-pipelining.test.js +78 -0
  140. package/test/close.test.js +706 -0
  141. package/test/conditional-pino.test.js +47 -0
  142. package/test/connection-timeout.test.js +42 -0
  143. package/test/constrained-routes.test.js +1138 -0
  144. package/test/content-length.test.js +174 -0
  145. package/test/content-parser.test.js +739 -0
  146. package/test/content-type.test.js +181 -0
  147. package/test/context-config.test.js +164 -0
  148. package/test/custom-http-server.test.js +118 -0
  149. package/test/custom-parser-async.test.js +59 -0
  150. package/test/custom-parser.0.test.js +701 -0
  151. package/test/custom-parser.1.test.js +266 -0
  152. package/test/custom-parser.2.test.js +91 -0
  153. package/test/custom-parser.3.test.js +208 -0
  154. package/test/custom-parser.4.test.js +218 -0
  155. package/test/custom-parser.5.test.js +130 -0
  156. package/test/custom-querystring-parser.test.js +129 -0
  157. package/test/decorator.test.js +1330 -0
  158. package/test/delete.test.js +344 -0
  159. package/test/diagnostics-channel/404.test.js +49 -0
  160. package/test/diagnostics-channel/async-delay-request.test.js +65 -0
  161. package/test/diagnostics-channel/async-request.test.js +64 -0
  162. package/test/diagnostics-channel/error-before-handler.test.js +35 -0
  163. package/test/diagnostics-channel/error-request.test.js +53 -0
  164. package/test/diagnostics-channel/error-status.test.js +123 -0
  165. package/test/diagnostics-channel/init.test.js +50 -0
  166. package/test/diagnostics-channel/sync-delay-request.test.js +49 -0
  167. package/test/diagnostics-channel/sync-request-reply.test.js +51 -0
  168. package/test/diagnostics-channel/sync-request.test.js +54 -0
  169. package/test/encapsulated-child-logger-factory.test.js +69 -0
  170. package/test/encapsulated-error-handler.test.js +237 -0
  171. package/test/esm/errorCodes.test.mjs +10 -0
  172. package/test/esm/esm.test.mjs +13 -0
  173. package/test/esm/index.test.js +8 -0
  174. package/test/esm/named-exports.mjs +14 -0
  175. package/test/esm/other.mjs +8 -0
  176. package/test/esm/plugin.mjs +8 -0
  177. package/test/fastify-instance.test.js +300 -0
  178. package/test/find-route.test.js +152 -0
  179. package/test/fluent-schema.test.js +209 -0
  180. package/test/genReqId.test.js +426 -0
  181. package/test/handler-context.test.js +45 -0
  182. package/test/handler-timeout.test.js +367 -0
  183. package/test/has-route.test.js +88 -0
  184. package/test/header-overflow.test.js +55 -0
  185. package/test/helper.js +496 -0
  186. package/test/hooks-async.test.js +1099 -0
  187. package/test/hooks.on-listen.test.js +1162 -0
  188. package/test/hooks.on-ready.test.js +421 -0
  189. package/test/hooks.test.js +3578 -0
  190. package/test/http-methods/copy.test.js +35 -0
  191. package/test/http-methods/custom-http-methods.test.js +114 -0
  192. package/test/http-methods/get.test.js +412 -0
  193. package/test/http-methods/head.test.js +263 -0
  194. package/test/http-methods/lock.test.js +108 -0
  195. package/test/http-methods/mkcalendar.test.js +143 -0
  196. package/test/http-methods/mkcol.test.js +35 -0
  197. package/test/http-methods/move.test.js +42 -0
  198. package/test/http-methods/propfind.test.js +136 -0
  199. package/test/http-methods/proppatch.test.js +105 -0
  200. package/test/http-methods/report.test.js +142 -0
  201. package/test/http-methods/search.test.js +233 -0
  202. package/test/http-methods/trace.test.js +21 -0
  203. package/test/http-methods/unlock.test.js +38 -0
  204. package/test/http2/closing.test.js +270 -0
  205. package/test/http2/constraint.test.js +109 -0
  206. package/test/http2/head.test.js +34 -0
  207. package/test/http2/plain.test.js +68 -0
  208. package/test/http2/secure-with-fallback.test.js +113 -0
  209. package/test/http2/secure.test.js +67 -0
  210. package/test/http2/unknown-http-method.test.js +34 -0
  211. package/test/https/custom-https-server.test.js +58 -0
  212. package/test/https/https.test.js +136 -0
  213. package/test/imports.test.js +17 -0
  214. package/test/inject.test.js +502 -0
  215. package/test/input-validation.js +335 -0
  216. package/test/internals/all.test.js +38 -0
  217. package/test/internals/content-type-parser.test.js +111 -0
  218. package/test/internals/context.test.js +31 -0
  219. package/test/internals/decorator.test.js +156 -0
  220. package/test/internals/errors.test.js +982 -0
  221. package/test/internals/handle-request.test.js +270 -0
  222. package/test/internals/hook-runner.test.js +449 -0
  223. package/test/internals/hooks.test.js +96 -0
  224. package/test/internals/initial-config.test.js +383 -0
  225. package/test/internals/logger.test.js +163 -0
  226. package/test/internals/plugin.test.js +170 -0
  227. package/test/internals/promise.test.js +63 -0
  228. package/test/internals/reply-serialize.test.js +714 -0
  229. package/test/internals/reply.test.js +1920 -0
  230. package/test/internals/req-id-gen-factory.test.js +133 -0
  231. package/test/internals/request-validate.test.js +1402 -0
  232. package/test/internals/request.test.js +506 -0
  233. package/test/internals/schema-controller-perf.test.js +40 -0
  234. package/test/internals/server.test.js +91 -0
  235. package/test/internals/validation.test.js +352 -0
  236. package/test/issue-4959.test.js +118 -0
  237. package/test/keep-alive-timeout.test.js +42 -0
  238. package/test/listen.1.test.js +154 -0
  239. package/test/listen.2.test.js +113 -0
  240. package/test/listen.3.test.js +83 -0
  241. package/test/listen.4.test.js +168 -0
  242. package/test/listen.5.test.js +122 -0
  243. package/test/logger/instantiation.test.js +341 -0
  244. package/test/logger/logger-test-utils.js +47 -0
  245. package/test/logger/logging.test.js +460 -0
  246. package/test/logger/options.test.js +579 -0
  247. package/test/logger/request.test.js +292 -0
  248. package/test/logger/response.test.js +183 -0
  249. package/test/logger/tap-parallel-not-ok +0 -0
  250. package/test/max-requests-per-socket.test.js +113 -0
  251. package/test/middleware.test.js +37 -0
  252. package/test/noop-set.test.js +19 -0
  253. package/test/nullable-validation.test.js +187 -0
  254. package/test/options.error-handler.test.js +5 -0
  255. package/test/options.test.js +5 -0
  256. package/test/output-validation.test.js +140 -0
  257. package/test/patch.error-handler.test.js +5 -0
  258. package/test/patch.test.js +5 -0
  259. package/test/plugin.1.test.js +230 -0
  260. package/test/plugin.2.test.js +314 -0
  261. package/test/plugin.3.test.js +287 -0
  262. package/test/plugin.4.test.js +504 -0
  263. package/test/plugin.helper.js +8 -0
  264. package/test/plugin.name.display.js +10 -0
  265. package/test/post-empty-body.test.js +38 -0
  266. package/test/pretty-print.test.js +366 -0
  267. package/test/promises.test.js +125 -0
  268. package/test/proto-poisoning.test.js +145 -0
  269. package/test/put.error-handler.test.js +5 -0
  270. package/test/put.test.js +5 -0
  271. package/test/register.test.js +184 -0
  272. package/test/reply-code.test.js +148 -0
  273. package/test/reply-early-hints.test.js +100 -0
  274. package/test/reply-error.test.js +815 -0
  275. package/test/reply-trailers.test.js +445 -0
  276. package/test/reply-web-stream-locked.test.js +37 -0
  277. package/test/request-error.test.js +624 -0
  278. package/test/request-header-host.test.js +339 -0
  279. package/test/request-id.test.js +118 -0
  280. package/test/request-timeout.test.js +53 -0
  281. package/test/route-hooks.test.js +635 -0
  282. package/test/route-prefix.test.js +904 -0
  283. package/test/route-shorthand.test.js +48 -0
  284. package/test/route.1.test.js +259 -0
  285. package/test/route.2.test.js +100 -0
  286. package/test/route.3.test.js +213 -0
  287. package/test/route.4.test.js +127 -0
  288. package/test/route.5.test.js +211 -0
  289. package/test/route.6.test.js +306 -0
  290. package/test/route.7.test.js +406 -0
  291. package/test/route.8.test.js +225 -0
  292. package/test/router-options.test.js +1108 -0
  293. package/test/same-shape.test.js +124 -0
  294. package/test/schema-examples.test.js +661 -0
  295. package/test/schema-feature.test.js +2198 -0
  296. package/test/schema-serialization.test.js +1171 -0
  297. package/test/schema-special-usage.test.js +1348 -0
  298. package/test/schema-validation.test.js +1572 -0
  299. package/test/scripts/validate-ecosystem-links.test.js +339 -0
  300. package/test/serialize-response.test.js +186 -0
  301. package/test/server.test.js +347 -0
  302. package/test/set-error-handler.test.js +69 -0
  303. package/test/skip-reply-send.test.js +317 -0
  304. package/test/stream-serializers.test.js +40 -0
  305. package/test/stream.1.test.js +94 -0
  306. package/test/stream.2.test.js +129 -0
  307. package/test/stream.3.test.js +198 -0
  308. package/test/stream.4.test.js +176 -0
  309. package/test/stream.5.test.js +188 -0
  310. package/test/sync-routes.test.js +32 -0
  311. package/test/throw.test.js +359 -0
  312. package/test/toolkit.js +63 -0
  313. package/test/trust-proxy.test.js +162 -0
  314. package/test/type-provider.test.js +22 -0
  315. package/test/types/content-type-parser.test-d.ts +72 -0
  316. package/test/types/decorate-request-reply.test-d.ts +18 -0
  317. package/test/types/dummy-plugin.ts +9 -0
  318. package/test/types/errors.test-d.ts +90 -0
  319. package/test/types/fastify.test-d.ts +352 -0
  320. package/test/types/hooks.test-d.ts +550 -0
  321. package/test/types/import.ts +2 -0
  322. package/test/types/instance.test-d.ts +588 -0
  323. package/test/types/logger.test-d.ts +277 -0
  324. package/test/types/plugin.test-d.ts +97 -0
  325. package/test/types/register.test-d.ts +237 -0
  326. package/test/types/reply.test-d.ts +254 -0
  327. package/test/types/request.test-d.ts +188 -0
  328. package/test/types/route.test-d.ts +553 -0
  329. package/test/types/schema.test-d.ts +135 -0
  330. package/test/types/serverFactory.test-d.ts +37 -0
  331. package/test/types/type-provider.test-d.ts +1213 -0
  332. package/test/types/using.test-d.ts +17 -0
  333. package/test/upgrade.test.js +52 -0
  334. package/test/url-rewriting.test.js +122 -0
  335. package/test/use-semicolon-delimiter.test.js +168 -0
  336. package/test/validation-error-handling.test.js +900 -0
  337. package/test/versioned-routes.test.js +603 -0
  338. package/test/web-api.test.js +616 -0
  339. package/test/wrap-thenable.test.js +30 -0
  340. package/types/content-type-parser.d.ts +75 -0
  341. package/types/context.d.ts +22 -0
  342. package/types/errors.d.ts +92 -0
  343. package/types/hooks.d.ts +875 -0
  344. package/types/instance.d.ts +609 -0
  345. package/types/logger.d.ts +107 -0
  346. package/types/plugin.d.ts +44 -0
  347. package/types/register.d.ts +42 -0
  348. package/types/reply.d.ts +81 -0
  349. package/types/request.d.ts +95 -0
  350. package/types/route.d.ts +199 -0
  351. package/types/schema.d.ts +61 -0
  352. package/types/server-factory.d.ts +19 -0
  353. package/types/type-provider.d.ts +130 -0
  354. 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
+ }
@@ -0,0 +1,10 @@
1
+ 'use strict'
2
+
3
+ module.exports = function noopSet () {
4
+ return {
5
+ [Symbol.iterator]: function * () {},
6
+ add () {},
7
+ delete () {},
8
+ has () { return true }
9
+ }
10
+ }
@@ -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
+ }