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
package/fastify.js ADDED
@@ -0,0 +1,985 @@
1
+ 'use strict'
2
+
3
+ const VERSION = '5.8.2'
4
+
5
+ const Avvio = require('avvio')
6
+ const http = require('node:http')
7
+ const diagnostics = require('node:diagnostics_channel')
8
+ let lightMyRequest
9
+
10
+ const {
11
+ kAvvioBoot,
12
+ kChildren,
13
+ kServerBindings,
14
+ kBodyLimit,
15
+ kSupportedHTTPMethods,
16
+ kRoutePrefix,
17
+ kLogLevel,
18
+ kLogSerializers,
19
+ kHooks,
20
+ kSchemaController,
21
+ kRequestAcceptVersion,
22
+ kReplySerializerDefault,
23
+ kContentTypeParser,
24
+ kReply,
25
+ kRequest,
26
+ kFourOhFour,
27
+ kState,
28
+ kOptions,
29
+ kPluginNameChain,
30
+ kSchemaErrorFormatter,
31
+ kErrorHandler,
32
+ kKeepAliveConnections,
33
+ kChildLoggerFactory,
34
+ kGenReqId,
35
+ kErrorHandlerAlreadySet,
36
+ kHandlerTimeout
37
+ } = require('./lib/symbols.js')
38
+
39
+ const { createServer } = require('./lib/server')
40
+ const Reply = require('./lib/reply')
41
+ const Request = require('./lib/request')
42
+ const Context = require('./lib/context.js')
43
+ const decorator = require('./lib/decorate')
44
+ const ContentTypeParser = require('./lib/content-type-parser.js')
45
+ const SchemaController = require('./lib/schema-controller')
46
+ const { Hooks, hookRunnerApplication, supportedHooks } = require('./lib/hooks')
47
+ const { createChildLogger, defaultChildLoggerFactory, createLogger } = require('./lib/logger-factory')
48
+ const pluginUtils = require('./lib/plugin-utils.js')
49
+ const { getGenReqId, reqIdGenFactory } = require('./lib/req-id-gen-factory.js')
50
+ const { buildRouting, validateBodyLimitOption, buildRouterOptions } = require('./lib/route')
51
+ const build404 = require('./lib/four-oh-four')
52
+ const getSecuredInitialConfig = require('./lib/initial-config-validation.js')
53
+ const override = require('./lib/plugin-override')
54
+ const {
55
+ appendStackTrace,
56
+ AVVIO_ERRORS_MAP,
57
+ ...errorCodes
58
+ } = require('./lib/errors')
59
+ const PonyPromise = require('./lib/promise')
60
+
61
+ const { defaultInitOptions } = getSecuredInitialConfig
62
+
63
+ const {
64
+ FST_ERR_ASYNC_CONSTRAINT,
65
+ FST_ERR_BAD_URL,
66
+ FST_ERR_OPTIONS_NOT_OBJ,
67
+ FST_ERR_QSP_NOT_FN,
68
+ FST_ERR_SCHEMA_CONTROLLER_BUCKET_OPT_NOT_FN,
69
+ FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_OBJ,
70
+ FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_ARR,
71
+ FST_ERR_INSTANCE_ALREADY_LISTENING,
72
+ FST_ERR_REOPENED_CLOSE_SERVER,
73
+ FST_ERR_ROUTE_REWRITE_NOT_STR,
74
+ FST_ERR_SCHEMA_ERROR_FORMATTER_NOT_FN,
75
+ FST_ERR_ERROR_HANDLER_NOT_FN,
76
+ FST_ERR_ERROR_HANDLER_ALREADY_SET,
77
+ FST_ERR_ROUTE_METHOD_INVALID
78
+ } = errorCodes
79
+
80
+ const { buildErrorHandler } = require('./lib/error-handler.js')
81
+ const { FSTWRN004 } = require('./lib/warnings.js')
82
+
83
+ const initChannel = diagnostics.channel('fastify.initialization')
84
+
85
+ /**
86
+ * @param {import('./fastify.js').FastifyServerOptions} serverOptions
87
+ */
88
+ function fastify (serverOptions) {
89
+ const {
90
+ options,
91
+ genReqId,
92
+ disableRequestLogging,
93
+ hasLogger,
94
+ initialConfig
95
+ } = processOptions(serverOptions, defaultRoute, onBadUrl)
96
+
97
+ // Default router
98
+ const router = buildRouting(options.routerOptions)
99
+
100
+ // 404 router, used for handling encapsulated 404 handlers
101
+ const fourOhFour = build404(options)
102
+
103
+ // HTTP server and its handler
104
+ const httpHandler = wrapRouting(router, options)
105
+
106
+ const {
107
+ server,
108
+ listen,
109
+ forceCloseConnections,
110
+ serverHasCloseAllConnections,
111
+ serverHasCloseHttp2Sessions,
112
+ keepAliveConnections
113
+ } = createServer(options, httpHandler)
114
+
115
+ const setupResponseListeners = Reply.setupResponseListeners
116
+ const schemaController = SchemaController.buildSchemaController(null, options.schemaController)
117
+
118
+ // Public API
119
+ const fastify = {
120
+ // Fastify internals
121
+ [kState]: {
122
+ listening: false,
123
+ closing: false,
124
+ started: false,
125
+ ready: false,
126
+ booting: false,
127
+ aborted: false,
128
+ readyResolver: null
129
+ },
130
+ [kKeepAliveConnections]: keepAliveConnections,
131
+ [kSupportedHTTPMethods]: {
132
+ bodyless: new Set([
133
+ // Standard
134
+ 'GET',
135
+ 'HEAD',
136
+ 'TRACE'
137
+ ]),
138
+ bodywith: new Set([
139
+ // Standard
140
+ 'DELETE',
141
+ 'OPTIONS',
142
+ 'PATCH',
143
+ 'PUT',
144
+ 'POST'
145
+ ])
146
+ },
147
+ [kOptions]: options,
148
+ [kChildren]: [],
149
+ [kServerBindings]: [],
150
+ [kBodyLimit]: options.bodyLimit,
151
+ [kHandlerTimeout]: options.handlerTimeout,
152
+ [kRoutePrefix]: '',
153
+ [kLogLevel]: '',
154
+ [kLogSerializers]: null,
155
+ [kHooks]: new Hooks(),
156
+ [kSchemaController]: schemaController,
157
+ [kSchemaErrorFormatter]: null,
158
+ [kErrorHandler]: buildErrorHandler(),
159
+ [kErrorHandlerAlreadySet]: false,
160
+ [kChildLoggerFactory]: options.childLoggerFactory || defaultChildLoggerFactory,
161
+ [kReplySerializerDefault]: null,
162
+ [kContentTypeParser]: new ContentTypeParser(
163
+ options.bodyLimit,
164
+ (options.onProtoPoisoning || defaultInitOptions.onProtoPoisoning),
165
+ (options.onConstructorPoisoning || defaultInitOptions.onConstructorPoisoning)
166
+ ),
167
+ [kReply]: Reply.buildReply(Reply),
168
+ [kRequest]: Request.buildRequest(Request, options.trustProxy),
169
+ [kFourOhFour]: fourOhFour,
170
+ [pluginUtils.kRegisteredPlugins]: [],
171
+ [kPluginNameChain]: ['fastify'],
172
+ [kAvvioBoot]: null,
173
+ [kGenReqId]: genReqId,
174
+ // routing method
175
+ routing: httpHandler,
176
+ // routes shorthand methods
177
+ delete: function _delete (url, options, handler) {
178
+ return router.prepareRoute.call(this, { method: 'DELETE', url, options, handler })
179
+ },
180
+ get: function _get (url, options, handler) {
181
+ return router.prepareRoute.call(this, { method: 'GET', url, options, handler })
182
+ },
183
+ head: function _head (url, options, handler) {
184
+ return router.prepareRoute.call(this, { method: 'HEAD', url, options, handler })
185
+ },
186
+ trace: function _trace (url, options, handler) {
187
+ return router.prepareRoute.call(this, { method: 'TRACE', url, options, handler })
188
+ },
189
+ patch: function _patch (url, options, handler) {
190
+ return router.prepareRoute.call(this, { method: 'PATCH', url, options, handler })
191
+ },
192
+ post: function _post (url, options, handler) {
193
+ return router.prepareRoute.call(this, { method: 'POST', url, options, handler })
194
+ },
195
+ put: function _put (url, options, handler) {
196
+ return router.prepareRoute.call(this, { method: 'PUT', url, options, handler })
197
+ },
198
+ options: function _options (url, options, handler) {
199
+ return router.prepareRoute.call(this, { method: 'OPTIONS', url, options, handler })
200
+ },
201
+ all: function _all (url, options, handler) {
202
+ return router.prepareRoute.call(this, { method: this.supportedMethods, url, options, handler })
203
+ },
204
+ // extended route
205
+ route: function _route (options) {
206
+ // we need the fastify object that we are producing so we apply a lazy loading of the function,
207
+ // otherwise we should bind it after the declaration
208
+ return router.route.call(this, { options })
209
+ },
210
+ hasRoute: function _route (options) {
211
+ return router.hasRoute.call(this, { options })
212
+ },
213
+ findRoute: function _findRoute (options) {
214
+ return router.findRoute(options)
215
+ },
216
+ // expose logger instance
217
+ log: options.logger,
218
+ // type provider
219
+ withTypeProvider,
220
+ // hooks
221
+ addHook,
222
+ // schemas
223
+ addSchema,
224
+ getSchema: schemaController.getSchema.bind(schemaController),
225
+ getSchemas: schemaController.getSchemas.bind(schemaController),
226
+ setValidatorCompiler,
227
+ setSerializerCompiler,
228
+ setSchemaController,
229
+ setReplySerializer,
230
+ setSchemaErrorFormatter,
231
+ // set generated request id
232
+ setGenReqId,
233
+ // custom parsers
234
+ addContentTypeParser: ContentTypeParser.helpers.addContentTypeParser,
235
+ hasContentTypeParser: ContentTypeParser.helpers.hasContentTypeParser,
236
+ getDefaultJsonParser: ContentTypeParser.defaultParsers.getDefaultJsonParser,
237
+ defaultTextParser: ContentTypeParser.defaultParsers.defaultTextParser,
238
+ removeContentTypeParser: ContentTypeParser.helpers.removeContentTypeParser,
239
+ removeAllContentTypeParsers: ContentTypeParser.helpers.removeAllContentTypeParsers,
240
+ // Fastify architecture methods (initialized by Avvio)
241
+ register: null,
242
+ after: null,
243
+ ready: null,
244
+ onClose: null,
245
+ close: null,
246
+ printPlugins: null,
247
+ hasPlugin: function (name) {
248
+ return this[pluginUtils.kRegisteredPlugins].includes(name) || this[kPluginNameChain].includes(name)
249
+ },
250
+ // http server
251
+ listen,
252
+ server,
253
+ addresses: function () {
254
+ /* istanbul ignore next */
255
+ const binded = this[kServerBindings].map(b => b.address())
256
+ binded.push(this.server.address())
257
+ return binded.filter(adr => adr)
258
+ },
259
+ // extend fastify objects
260
+ decorate: decorator.add,
261
+ hasDecorator: decorator.exist,
262
+ decorateReply: decorator.decorateReply,
263
+ decorateRequest: decorator.decorateRequest,
264
+ hasRequestDecorator: decorator.existRequest,
265
+ hasReplyDecorator: decorator.existReply,
266
+ getDecorator: decorator.getInstanceDecorator,
267
+ addHttpMethod,
268
+ // fake http injection
269
+ inject,
270
+ // pretty print of the registered routes
271
+ printRoutes,
272
+ // custom error handling
273
+ setNotFoundHandler,
274
+ setErrorHandler,
275
+ // child logger
276
+ setChildLoggerFactory,
277
+ // Set fastify initial configuration options read-only object
278
+ initialConfig,
279
+ // constraint strategies
280
+ addConstraintStrategy: router.addConstraintStrategy.bind(router),
281
+ hasConstraintStrategy: router.hasConstraintStrategy.bind(router)
282
+ }
283
+
284
+ Object.defineProperties(fastify, {
285
+ listeningOrigin: {
286
+ get () {
287
+ const address = this.addresses().slice(-1).pop()
288
+ /* ignore if windows: unix socket is not testable on Windows platform */
289
+ /* c8 ignore next 3 */
290
+ if (typeof address === 'string') {
291
+ return address
292
+ }
293
+ const host = address.family === 'IPv6' ? `[${address.address}]` : address.address
294
+ return `${this[kOptions].https ? 'https' : 'http'}://${host}:${address.port}`
295
+ }
296
+ },
297
+ pluginName: {
298
+ configurable: true,
299
+ get () {
300
+ if (this[kPluginNameChain].length > 1) {
301
+ return this[kPluginNameChain].join(' -> ')
302
+ }
303
+ return this[kPluginNameChain][0]
304
+ }
305
+ },
306
+ prefix: {
307
+ configurable: true,
308
+ get () { return this[kRoutePrefix] }
309
+ },
310
+ validatorCompiler: {
311
+ configurable: true,
312
+ get () { return this[kSchemaController].getValidatorCompiler() }
313
+ },
314
+ serializerCompiler: {
315
+ configurable: true,
316
+ get () { return this[kSchemaController].getSerializerCompiler() }
317
+ },
318
+ childLoggerFactory: {
319
+ configurable: true,
320
+ get () { return this[kChildLoggerFactory] }
321
+ },
322
+ version: {
323
+ configurable: true,
324
+ get () { return VERSION }
325
+ },
326
+ errorHandler: {
327
+ configurable: true,
328
+ get () {
329
+ return this[kErrorHandler].func
330
+ }
331
+ },
332
+ genReqId: {
333
+ configurable: true,
334
+ get () { return this[kGenReqId] }
335
+ },
336
+ supportedMethods: {
337
+ configurable: false,
338
+ get () {
339
+ return [
340
+ ...this[kSupportedHTTPMethods].bodyless,
341
+ ...this[kSupportedHTTPMethods].bodywith
342
+ ]
343
+ }
344
+ }
345
+ })
346
+
347
+ if (options.schemaErrorFormatter) {
348
+ validateSchemaErrorFormatter(options.schemaErrorFormatter)
349
+ fastify[kSchemaErrorFormatter] = options.schemaErrorFormatter.bind(fastify)
350
+ }
351
+
352
+ // Install and configure Avvio
353
+ // Avvio will update the following Fastify methods:
354
+ // - register
355
+ // - after
356
+ // - ready
357
+ // - onClose
358
+ // - close
359
+
360
+ const avvioPluginTimeout = Number(options.pluginTimeout)
361
+ const avvio = Avvio(fastify, {
362
+ autostart: false,
363
+ timeout: isNaN(avvioPluginTimeout) === false ? avvioPluginTimeout : defaultInitOptions.pluginTimeout,
364
+ expose: {
365
+ use: 'register'
366
+ }
367
+ })
368
+ // Override to allow the plugin encapsulation
369
+ avvio.override = override
370
+ avvio.on('start', () => (fastify[kState].started = true))
371
+ fastify[kAvvioBoot] = fastify.ready // the avvio ready function
372
+ fastify.ready = ready // overwrite the avvio ready function
373
+ fastify.printPlugins = avvio.prettyPrint.bind(avvio)
374
+
375
+ // cache the closing value, since we are checking it in an hot path
376
+ avvio.once('preReady', () => {
377
+ fastify.onClose((instance, done) => {
378
+ fastify[kState].closing = true
379
+ router.closeRoutes()
380
+
381
+ hookRunnerApplication('preClose', fastify[kAvvioBoot], fastify, function () {
382
+ if (fastify[kState].listening) {
383
+ /* istanbul ignore next: Cannot test this without Node.js core support */
384
+ if (forceCloseConnections === 'idle') {
385
+ // Not needed in Node 19
386
+ instance.server.closeIdleConnections()
387
+ /* istanbul ignore next: Cannot test this without Node.js core support */
388
+ } else if (serverHasCloseAllConnections && forceCloseConnections) {
389
+ instance.server.closeAllConnections()
390
+ } else if (forceCloseConnections === true) {
391
+ for (const conn of fastify[kKeepAliveConnections]) {
392
+ // We must invoke the destroy method instead of merely unreffing
393
+ // the sockets. If we only unref, then the callback passed to
394
+ // `fastify.close` will never be invoked; nor will any of the
395
+ // registered `onClose` hooks.
396
+ conn.destroy()
397
+ fastify[kKeepAliveConnections].delete(conn)
398
+ }
399
+ }
400
+ }
401
+
402
+ if (serverHasCloseHttp2Sessions) {
403
+ instance.server.closeHttp2Sessions()
404
+ }
405
+
406
+ // No new TCP connections are accepted.
407
+ // We must call close on the server even if we are not listening
408
+ // otherwise memory will be leaked.
409
+ // https://github.com/nodejs/node/issues/48604
410
+ if (!options.serverFactory || fastify[kState].listening) {
411
+ instance.server.close(function (err) {
412
+ /* c8 ignore next 6 */
413
+ if (err && err.code !== 'ERR_SERVER_NOT_RUNNING') {
414
+ done(null)
415
+ } else {
416
+ done()
417
+ }
418
+ })
419
+ } else {
420
+ process.nextTick(done, null)
421
+ }
422
+ })
423
+ })
424
+ })
425
+
426
+ // Create bad URL context
427
+ const onBadUrlContext = new Context({
428
+ server: fastify,
429
+ config: {}
430
+ })
431
+
432
+ // Set the default 404 handler
433
+ fastify.setNotFoundHandler()
434
+ fourOhFour.arrange404(fastify)
435
+
436
+ router.setup(options, {
437
+ avvio,
438
+ fourOhFour,
439
+ hasLogger,
440
+ setupResponseListeners,
441
+ throwIfAlreadyStarted,
442
+ keepAliveConnections
443
+ })
444
+
445
+ // Delay configuring clientError handler so that it can access fastify state.
446
+ server.on('clientError', options.clientErrorHandler.bind(fastify))
447
+
448
+ if (initChannel.hasSubscribers) {
449
+ initChannel.publish({ fastify })
450
+ }
451
+
452
+ // Older nodejs versions may not have asyncDispose
453
+ if ('asyncDispose' in Symbol) {
454
+ fastify[Symbol.asyncDispose] = function dispose () {
455
+ return fastify.close()
456
+ }
457
+ }
458
+
459
+ return fastify
460
+
461
+ function throwIfAlreadyStarted (msg) {
462
+ if (fastify[kState].started) throw new FST_ERR_INSTANCE_ALREADY_LISTENING(msg)
463
+ }
464
+
465
+ // HTTP injection handling
466
+ // If the server is not ready yet, this
467
+ // utility will automatically force it.
468
+ function inject (opts, cb) {
469
+ // lightMyRequest is dynamically loaded as it seems very expensive
470
+ // because of Ajv
471
+ if (lightMyRequest === undefined) {
472
+ lightMyRequest = require('light-my-request')
473
+ }
474
+
475
+ if (fastify[kState].started) {
476
+ if (fastify[kState].closing) {
477
+ // Force to return an error
478
+ const error = new FST_ERR_REOPENED_CLOSE_SERVER()
479
+ if (cb) {
480
+ cb(error)
481
+ return
482
+ } else {
483
+ return Promise.reject(error)
484
+ }
485
+ }
486
+ return lightMyRequest(httpHandler, opts, cb)
487
+ }
488
+
489
+ if (cb) {
490
+ this.ready(err => {
491
+ if (err) cb(err, null)
492
+ else lightMyRequest(httpHandler, opts, cb)
493
+ })
494
+ } else {
495
+ return lightMyRequest((req, res) => {
496
+ this.ready(function (err) {
497
+ if (err) {
498
+ res.emit('error', err)
499
+ return
500
+ }
501
+ httpHandler(req, res)
502
+ })
503
+ }, opts)
504
+ }
505
+ }
506
+
507
+ function ready (cb) {
508
+ if (this[kState].readyResolver !== null) {
509
+ if (cb != null) {
510
+ this[kState].readyResolver.promise.then(() => cb(null, fastify), cb)
511
+ return
512
+ }
513
+
514
+ return this[kState].readyResolver.promise
515
+ }
516
+
517
+ // run the hooks after returning the promise
518
+ process.nextTick(runHooks)
519
+
520
+ // Create a promise no matter what
521
+ // It will work as a barrier for all the .ready() calls (ensuring single hook execution)
522
+ // as well as a flow control mechanism to chain cbs and further
523
+ // promises
524
+ this[kState].readyResolver = PonyPromise.withResolvers()
525
+
526
+ if (!cb) {
527
+ return this[kState].readyResolver.promise
528
+ } else {
529
+ this[kState].readyResolver.promise.then(() => cb(null, fastify), cb)
530
+ }
531
+
532
+ function runHooks () {
533
+ // start loading
534
+ fastify[kAvvioBoot]((err, done) => {
535
+ if (err || fastify[kState].started || fastify[kState].ready || fastify[kState].booting) {
536
+ manageErr(err)
537
+ } else {
538
+ fastify[kState].booting = true
539
+ hookRunnerApplication('onReady', fastify[kAvvioBoot], fastify, manageErr)
540
+ }
541
+ done()
542
+ })
543
+ }
544
+
545
+ function manageErr (err) {
546
+ // If the error comes out of Avvio's Error codes
547
+ // We create a make and preserve the previous error
548
+ // as cause
549
+ err = err != null && AVVIO_ERRORS_MAP[err.code] != null
550
+ ? appendStackTrace(err, new AVVIO_ERRORS_MAP[err.code](err.message))
551
+ : err
552
+
553
+ if (err) {
554
+ return fastify[kState].readyResolver.reject(err)
555
+ }
556
+
557
+ fastify[kState].readyResolver.resolve(fastify)
558
+ fastify[kState].booting = false
559
+ fastify[kState].ready = true
560
+ fastify[kState].readyResolver = null
561
+ }
562
+ }
563
+
564
+ // Used exclusively in TypeScript contexts to enable auto type inference from JSON schema.
565
+ function withTypeProvider () {
566
+ return this
567
+ }
568
+
569
+ // wrapper that we expose to the user for hooks handling
570
+ function addHook (name, fn) {
571
+ throwIfAlreadyStarted('Cannot call "addHook"!')
572
+
573
+ if (fn == null) {
574
+ throw new errorCodes.FST_ERR_HOOK_INVALID_HANDLER(name, fn)
575
+ }
576
+
577
+ if (name === 'onSend' || name === 'preSerialization' || name === 'onError' || name === 'preParsing') {
578
+ if (fn.constructor.name === 'AsyncFunction' && fn.length === 4) {
579
+ throw new errorCodes.FST_ERR_HOOK_INVALID_ASYNC_HANDLER()
580
+ }
581
+ } else if (name === 'onReady' || name === 'onListen') {
582
+ if (fn.constructor.name === 'AsyncFunction' && fn.length !== 0) {
583
+ throw new errorCodes.FST_ERR_HOOK_INVALID_ASYNC_HANDLER()
584
+ }
585
+ } else if (name === 'onRequestAbort') {
586
+ if (fn.constructor.name === 'AsyncFunction' && fn.length !== 1) {
587
+ throw new errorCodes.FST_ERR_HOOK_INVALID_ASYNC_HANDLER()
588
+ }
589
+ } else {
590
+ if (fn.constructor.name === 'AsyncFunction' && fn.length === 3) {
591
+ throw new errorCodes.FST_ERR_HOOK_INVALID_ASYNC_HANDLER()
592
+ }
593
+ }
594
+
595
+ if (name === 'onClose') {
596
+ this.onClose(fn.bind(this))
597
+ } else if (name === 'onReady' || name === 'onListen' || name === 'onRoute') {
598
+ this[kHooks].add(name, fn)
599
+ } else {
600
+ this.after((err, done) => {
601
+ try {
602
+ _addHook.call(this, name, fn)
603
+ done(err)
604
+ } catch (err) {
605
+ done(err)
606
+ }
607
+ })
608
+ }
609
+ return this
610
+
611
+ function _addHook (name, fn) {
612
+ this[kHooks].add(name, fn)
613
+ this[kChildren].forEach(child => _addHook.call(child, name, fn))
614
+ }
615
+ }
616
+
617
+ // wrapper that we expose to the user for schemas handling
618
+ function addSchema (schema) {
619
+ throwIfAlreadyStarted('Cannot call "addSchema"!')
620
+ this[kSchemaController].add(schema)
621
+ this[kChildren].forEach(child => child.addSchema(schema))
622
+ return this
623
+ }
624
+
625
+ // If the router does not match any route, every request will land here
626
+ // req and res are Node.js core objects
627
+ function defaultRoute (req, res) {
628
+ if (req.headers['accept-version'] !== undefined) {
629
+ // we remove the accept-version header for performance result
630
+ // because we do not want to go through the constraint checking
631
+ // the usage of symbol here to prevent any collision on custom header name
632
+ req.headers[kRequestAcceptVersion] = req.headers['accept-version']
633
+ req.headers['accept-version'] = undefined
634
+ }
635
+ fourOhFour.router.lookup(req, res)
636
+ }
637
+
638
+ function onBadUrl (path, req, res) {
639
+ if (options.frameworkErrors) {
640
+ const id = getGenReqId(onBadUrlContext.server, req)
641
+ const childLogger = createChildLogger(onBadUrlContext, options.logger, req, id)
642
+
643
+ const request = new Request(id, null, req, null, childLogger, onBadUrlContext)
644
+ const reply = new Reply(res, request, childLogger)
645
+
646
+ const resolvedDisableRequestLogging = typeof disableRequestLogging === 'function' ? disableRequestLogging(req) : disableRequestLogging
647
+ if (resolvedDisableRequestLogging === false) {
648
+ childLogger.info({ req: request }, 'incoming request')
649
+ }
650
+
651
+ return options.frameworkErrors(new FST_ERR_BAD_URL(path), request, reply)
652
+ }
653
+ const body = JSON.stringify({
654
+ error: 'Bad Request',
655
+ code: 'FST_ERR_BAD_URL',
656
+ message: `'${path}' is not a valid url component`,
657
+ statusCode: 400
658
+ })
659
+ res.writeHead(400, {
660
+ 'Content-Type': 'application/json',
661
+ 'Content-Length': Buffer.byteLength(body)
662
+ })
663
+ res.end(body)
664
+ }
665
+
666
+ function buildAsyncConstraintCallback (isAsync, req, res) {
667
+ if (isAsync === false) return undefined
668
+ return function onAsyncConstraintError (err) {
669
+ if (err) {
670
+ if (options.frameworkErrors) {
671
+ const id = getGenReqId(onBadUrlContext.server, req)
672
+ const childLogger = createChildLogger(onBadUrlContext, options.logger, req, id)
673
+
674
+ const request = new Request(id, null, req, null, childLogger, onBadUrlContext)
675
+ const reply = new Reply(res, request, childLogger)
676
+
677
+ const resolvedDisableRequestLogging = typeof disableRequestLogging === 'function' ? disableRequestLogging(req) : disableRequestLogging
678
+ if (resolvedDisableRequestLogging === false) {
679
+ childLogger.info({ req: request }, 'incoming request')
680
+ }
681
+
682
+ return options.frameworkErrors(new FST_ERR_ASYNC_CONSTRAINT(), request, reply)
683
+ }
684
+ const body = '{"error":"Internal Server Error","message":"Unexpected error from async constraint","statusCode":500}'
685
+ res.writeHead(500, {
686
+ 'Content-Type': 'application/json',
687
+ 'Content-Length': body.length
688
+ })
689
+ res.end(body)
690
+ }
691
+ }
692
+ }
693
+
694
+ function setNotFoundHandler (opts, handler) {
695
+ throwIfAlreadyStarted('Cannot call "setNotFoundHandler"!')
696
+
697
+ fourOhFour.setNotFoundHandler.call(this, opts, handler, avvio, router.routeHandler)
698
+ return this
699
+ }
700
+
701
+ function setValidatorCompiler (validatorCompiler) {
702
+ throwIfAlreadyStarted('Cannot call "setValidatorCompiler"!')
703
+ this[kSchemaController].setValidatorCompiler(validatorCompiler)
704
+ return this
705
+ }
706
+
707
+ function setSchemaErrorFormatter (errorFormatter) {
708
+ throwIfAlreadyStarted('Cannot call "setSchemaErrorFormatter"!')
709
+ validateSchemaErrorFormatter(errorFormatter)
710
+ this[kSchemaErrorFormatter] = errorFormatter.bind(this)
711
+ return this
712
+ }
713
+
714
+ function setSerializerCompiler (serializerCompiler) {
715
+ throwIfAlreadyStarted('Cannot call "setSerializerCompiler"!')
716
+ this[kSchemaController].setSerializerCompiler(serializerCompiler)
717
+ return this
718
+ }
719
+
720
+ function setSchemaController (schemaControllerOpts) {
721
+ throwIfAlreadyStarted('Cannot call "setSchemaController"!')
722
+ const old = this[kSchemaController]
723
+ const schemaController = SchemaController.buildSchemaController(
724
+ old,
725
+ Object.assign({}, old.opts, schemaControllerOpts)
726
+ )
727
+ this[kSchemaController] = schemaController
728
+ this.getSchema = schemaController.getSchema.bind(schemaController)
729
+ this.getSchemas = schemaController.getSchemas.bind(schemaController)
730
+ return this
731
+ }
732
+
733
+ function setReplySerializer (replySerializer) {
734
+ throwIfAlreadyStarted('Cannot call "setReplySerializer"!')
735
+
736
+ this[kReplySerializerDefault] = replySerializer
737
+ return this
738
+ }
739
+
740
+ // wrapper that we expose to the user for configure the custom error handler
741
+ function setErrorHandler (func) {
742
+ throwIfAlreadyStarted('Cannot call "setErrorHandler"!')
743
+
744
+ if (typeof func !== 'function') {
745
+ throw new FST_ERR_ERROR_HANDLER_NOT_FN()
746
+ }
747
+
748
+ if (!options.allowErrorHandlerOverride && this[kErrorHandlerAlreadySet]) {
749
+ throw new FST_ERR_ERROR_HANDLER_ALREADY_SET()
750
+ } else if (this[kErrorHandlerAlreadySet]) {
751
+ FSTWRN004("To disable this behavior, set 'allowErrorHandlerOverride' to false or ignore this message. For more information, visit: https://fastify.dev/docs/latest/Reference/Server/#allowerrorhandleroverride")
752
+ }
753
+
754
+ this[kErrorHandlerAlreadySet] = true
755
+ this[kErrorHandler] = buildErrorHandler(this[kErrorHandler], func.bind(this))
756
+ return this
757
+ }
758
+
759
+ function setChildLoggerFactory (factory) {
760
+ throwIfAlreadyStarted('Cannot call "setChildLoggerFactory"!')
761
+
762
+ this[kChildLoggerFactory] = factory
763
+ return this
764
+ }
765
+
766
+ function printRoutes (opts = {}) {
767
+ // includeHooks:true - shortcut to include all supported hooks exported by fastify.Hooks
768
+ opts.includeMeta = opts.includeHooks
769
+ ? opts.includeMeta ? supportedHooks.concat(opts.includeMeta) : supportedHooks
770
+ : opts.includeMeta
771
+ return router.printRoutes(opts)
772
+ }
773
+
774
+ function wrapRouting (router, { rewriteUrl, logger }) {
775
+ let isAsync
776
+ return function preRouting (req, res) {
777
+ // only call isAsyncConstraint once
778
+ if (isAsync === undefined) isAsync = router.isAsyncConstraint()
779
+ if (rewriteUrl) {
780
+ req.originalUrl = req.url
781
+ const url = rewriteUrl.call(fastify, req)
782
+ if (typeof url === 'string') {
783
+ req.url = url
784
+ } else {
785
+ const err = new FST_ERR_ROUTE_REWRITE_NOT_STR(req.url, typeof url)
786
+ req.destroy(err)
787
+ }
788
+ }
789
+ router.routing(req, res, buildAsyncConstraintCallback(isAsync, req, res))
790
+ }
791
+ }
792
+
793
+ function setGenReqId (func) {
794
+ throwIfAlreadyStarted('Cannot call "setGenReqId"!')
795
+
796
+ this[kGenReqId] = reqIdGenFactory(this[kOptions].requestIdHeader, func)
797
+ return this
798
+ }
799
+
800
+ function addHttpMethod (method, { hasBody = false } = {}) {
801
+ if (typeof method !== 'string' || http.METHODS.indexOf(method) === -1) {
802
+ throw new FST_ERR_ROUTE_METHOD_INVALID()
803
+ }
804
+
805
+ if (hasBody === true) {
806
+ this[kSupportedHTTPMethods].bodywith.add(method)
807
+ this[kSupportedHTTPMethods].bodyless.delete(method)
808
+ } else {
809
+ this[kSupportedHTTPMethods].bodywith.delete(method)
810
+ this[kSupportedHTTPMethods].bodyless.add(method)
811
+ }
812
+
813
+ const _method = method.toLowerCase()
814
+ if (!this.hasDecorator(_method)) {
815
+ this.decorate(_method, function (url, options, handler) {
816
+ return router.prepareRoute.call(this, { method, url, options, handler })
817
+ })
818
+ }
819
+
820
+ return this
821
+ }
822
+ }
823
+
824
+ function processOptions (options, defaultRoute, onBadUrl) {
825
+ // Options validations
826
+ if (options && typeof options !== 'object') {
827
+ throw new FST_ERR_OPTIONS_NOT_OBJ()
828
+ } else {
829
+ // Shallow copy options object to prevent mutations outside of this function
830
+ options = Object.assign({}, options)
831
+ }
832
+
833
+ if (
834
+ (options.querystringParser && typeof options.querystringParser !== 'function') ||
835
+ (
836
+ options.routerOptions?.querystringParser &&
837
+ typeof options.routerOptions.querystringParser !== 'function'
838
+ )
839
+ ) {
840
+ throw new FST_ERR_QSP_NOT_FN(typeof (options.querystringParser ?? options.routerOptions.querystringParser))
841
+ }
842
+
843
+ if (options.schemaController && options.schemaController.bucket && typeof options.schemaController.bucket !== 'function') {
844
+ throw new FST_ERR_SCHEMA_CONTROLLER_BUCKET_OPT_NOT_FN(typeof options.schemaController.bucket)
845
+ }
846
+
847
+ validateBodyLimitOption(options.bodyLimit)
848
+
849
+ const requestIdHeader = typeof options.requestIdHeader === 'string' && options.requestIdHeader.length !== 0 ? options.requestIdHeader.toLowerCase() : (options.requestIdHeader === true && 'request-id')
850
+ const genReqId = reqIdGenFactory(requestIdHeader, options.genReqId)
851
+ const requestIdLogLabel = options.requestIdLogLabel || 'reqId'
852
+ options.bodyLimit = options.bodyLimit || defaultInitOptions.bodyLimit
853
+ const disableRequestLogging = options.disableRequestLogging || false
854
+
855
+ const ajvOptions = Object.assign({
856
+ customOptions: {},
857
+ plugins: []
858
+ }, options.ajv)
859
+
860
+ if (!ajvOptions.customOptions || Object.prototype.toString.call(ajvOptions.customOptions) !== '[object Object]') {
861
+ throw new FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_OBJ(typeof ajvOptions.customOptions)
862
+ }
863
+ if (!ajvOptions.plugins || !Array.isArray(ajvOptions.plugins)) {
864
+ throw new FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_ARR(typeof ajvOptions.plugins)
865
+ }
866
+
867
+ const { logger, hasLogger } = createLogger(options)
868
+
869
+ // Update the options with the fixed values
870
+ options.connectionTimeout = options.connectionTimeout || defaultInitOptions.connectionTimeout
871
+ options.keepAliveTimeout = options.keepAliveTimeout || defaultInitOptions.keepAliveTimeout
872
+ options.maxRequestsPerSocket = options.maxRequestsPerSocket || defaultInitOptions.maxRequestsPerSocket
873
+ options.requestTimeout = options.requestTimeout || defaultInitOptions.requestTimeout
874
+ options.logger = logger
875
+ options.requestIdHeader = requestIdHeader
876
+ options.requestIdLogLabel = requestIdLogLabel
877
+ options.disableRequestLogging = disableRequestLogging
878
+ options.ajv = ajvOptions
879
+ options.clientErrorHandler = options.clientErrorHandler || defaultClientErrorHandler
880
+ options.allowErrorHandlerOverride = options.allowErrorHandlerOverride ?? defaultInitOptions.allowErrorHandlerOverride
881
+
882
+ const initialConfig = getSecuredInitialConfig(options)
883
+
884
+ // exposeHeadRoutes have its default set from the validator
885
+ options.exposeHeadRoutes = initialConfig.exposeHeadRoutes
886
+
887
+ // we need to set this before calling createServer
888
+ options.http2SessionTimeout = initialConfig.http2SessionTimeout
889
+
890
+ options.routerOptions = buildRouterOptions(options, {
891
+ defaultRoute,
892
+ onBadUrl,
893
+ ignoreTrailingSlash: defaultInitOptions.ignoreTrailingSlash,
894
+ ignoreDuplicateSlashes: defaultInitOptions.ignoreDuplicateSlashes,
895
+ maxParamLength: defaultInitOptions.maxParamLength,
896
+ allowUnsafeRegex: defaultInitOptions.allowUnsafeRegex,
897
+ buildPrettyMeta: defaultBuildPrettyMeta,
898
+ useSemicolonDelimiter: defaultInitOptions.useSemicolonDelimiter
899
+ })
900
+
901
+ return {
902
+ options,
903
+ genReqId,
904
+ disableRequestLogging,
905
+ hasLogger,
906
+ initialConfig
907
+ }
908
+ }
909
+
910
+ function defaultBuildPrettyMeta (route) {
911
+ // return a shallow copy of route's sanitized context
912
+
913
+ const cleanKeys = {}
914
+ const allowedProps = ['errorHandler', 'logLevel', 'logSerializers']
915
+
916
+ allowedProps.concat(supportedHooks).forEach(k => {
917
+ cleanKeys[k] = route.store[k]
918
+ })
919
+
920
+ return Object.assign({}, cleanKeys)
921
+ }
922
+
923
+ function defaultClientErrorHandler (err, socket) {
924
+ // In case of a connection reset, the socket has been destroyed and there is nothing that needs to be done.
925
+ // https://nodejs.org/api/http.html#http_event_clienterror
926
+ if (err.code === 'ECONNRESET' || socket.destroyed) {
927
+ return
928
+ }
929
+
930
+ let body, errorCode, errorStatus, errorLabel
931
+
932
+ if (err.code === 'ERR_HTTP_REQUEST_TIMEOUT') {
933
+ errorCode = '408'
934
+ errorStatus = http.STATUS_CODES[errorCode]
935
+ body = `{"error":"${errorStatus}","message":"Client Timeout","statusCode":408}`
936
+ errorLabel = 'timeout'
937
+ } else if (err.code === 'HPE_HEADER_OVERFLOW') {
938
+ errorCode = '431'
939
+ errorStatus = http.STATUS_CODES[errorCode]
940
+ body = `{"error":"${errorStatus}","message":"Exceeded maximum allowed HTTP header size","statusCode":431}`
941
+ errorLabel = 'header_overflow'
942
+ } else {
943
+ errorCode = '400'
944
+ errorStatus = http.STATUS_CODES[errorCode]
945
+ body = `{"error":"${errorStatus}","message":"Client Error","statusCode":400}`
946
+ errorLabel = 'error'
947
+ }
948
+
949
+ // Most devs do not know what to do with this error.
950
+ // In the vast majority of cases, it's a network error and/or some
951
+ // config issue on the load balancer side.
952
+ this.log.trace({ err }, `client ${errorLabel}`)
953
+ // Copying standard node behavior
954
+ // https://github.com/nodejs/node/blob/6ca23d7846cb47e84fd344543e394e50938540be/lib/_http_server.js#L666
955
+
956
+ // If the socket is not writable, there is no reason to try to send data.
957
+ if (socket.writable) {
958
+ socket.write(`HTTP/1.1 ${errorCode} ${errorStatus}\r\nContent-Length: ${body.length}\r\nContent-Type: application/json\r\n\r\n${body}`)
959
+ }
960
+ socket.destroy(err)
961
+ }
962
+
963
+ function validateSchemaErrorFormatter (schemaErrorFormatter) {
964
+ if (typeof schemaErrorFormatter !== 'function') {
965
+ throw new FST_ERR_SCHEMA_ERROR_FORMATTER_NOT_FN(typeof schemaErrorFormatter)
966
+ } else if (schemaErrorFormatter.constructor.name === 'AsyncFunction') {
967
+ throw new FST_ERR_SCHEMA_ERROR_FORMATTER_NOT_FN('AsyncFunction')
968
+ }
969
+ }
970
+
971
+ /**
972
+ * These export configurations enable JS and TS developers
973
+ * to consume fastify in whatever way best suits their needs.
974
+ * Some examples of supported import syntax includes:
975
+ * - `const fastify = require('fastify')`
976
+ * - `const { fastify } = require('fastify')`
977
+ * - `import * as Fastify from 'fastify'`
978
+ * - `import { fastify, TSC_definition } from 'fastify'`
979
+ * - `import fastify from 'fastify'`
980
+ * - `import fastify, { TSC_definition } from 'fastify'`
981
+ */
982
+ module.exports = fastify
983
+ module.exports.errorCodes = errorCodes
984
+ module.exports.fastify = fastify
985
+ module.exports.default = fastify