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,292 @@
1
+ 'use strict'
2
+
3
+ const stream = require('node:stream')
4
+
5
+ const t = require('node:test')
6
+ const split = require('split2')
7
+
8
+ const Fastify = require('../../fastify')
9
+ const helper = require('../helper')
10
+ const { on } = stream
11
+ const { request } = require('./logger-test-utils')
12
+ const { partialDeepStrictEqual } = require('../toolkit')
13
+
14
+ t.test('request', { timeout: 60000 }, async (t) => {
15
+ let localhost
16
+
17
+ t.plan(7)
18
+ t.before(async function () {
19
+ [localhost] = await helper.getLoopbackHost()
20
+ })
21
+
22
+ await t.test('The request id header key can be customized', async (t) => {
23
+ const lines = ['incoming request', 'some log message', 'request completed']
24
+ t.plan(lines.length * 2 + 2)
25
+ const REQUEST_ID = '42'
26
+
27
+ const stream = split(JSON.parse)
28
+ const fastify = Fastify({
29
+ logger: { stream, level: 'info' },
30
+ requestIdHeader: 'my-custom-request-id'
31
+ })
32
+ t.after(() => fastify.close())
33
+
34
+ fastify.get('/', (req, reply) => {
35
+ t.assert.strictEqual(req.id, REQUEST_ID)
36
+ req.log.info('some log message')
37
+ reply.send({ id: req.id })
38
+ })
39
+
40
+ const response = await fastify.inject({ method: 'GET', url: '/', headers: { 'my-custom-request-id': REQUEST_ID } })
41
+ const body = await response.json()
42
+ t.assert.strictEqual(body.id, REQUEST_ID)
43
+
44
+ for await (const [line] of on(stream, 'data')) {
45
+ t.assert.strictEqual(line.reqId, REQUEST_ID)
46
+ t.assert.strictEqual(line.msg, lines.shift(), 'message is set')
47
+ if (lines.length === 0) break
48
+ }
49
+ })
50
+
51
+ await t.test('The request id header key can be ignored', async (t) => {
52
+ const lines = ['incoming request', 'some log message', 'request completed']
53
+ t.plan(lines.length * 2 + 2)
54
+ const REQUEST_ID = 'ignore-me'
55
+
56
+ const stream = split(JSON.parse)
57
+ const fastify = Fastify({
58
+ logger: { stream, level: 'info' },
59
+ requestIdHeader: false
60
+ })
61
+ t.after(() => fastify.close())
62
+
63
+ fastify.get('/', (req, reply) => {
64
+ t.assert.strictEqual(req.id, 'req-1')
65
+ req.log.info('some log message')
66
+ reply.send({ id: req.id })
67
+ })
68
+ const response = await fastify.inject({ method: 'GET', url: '/', headers: { 'request-id': REQUEST_ID } })
69
+ const body = await response.json()
70
+ t.assert.strictEqual(body.id, 'req-1')
71
+
72
+ for await (const [line] of on(stream, 'data')) {
73
+ t.assert.strictEqual(line.reqId, 'req-1')
74
+ t.assert.strictEqual(line.msg, lines.shift(), 'message is set')
75
+ if (lines.length === 0) break
76
+ }
77
+ })
78
+
79
+ await t.test('The request id header key can be customized along with a custom id generator', async (t) => {
80
+ const REQUEST_ID = '42'
81
+ const matches = [
82
+ { reqId: REQUEST_ID, msg: 'incoming request' },
83
+ { reqId: REQUEST_ID, msg: 'some log message' },
84
+ { reqId: REQUEST_ID, msg: 'request completed' },
85
+ { reqId: 'foo', msg: 'incoming request' },
86
+ { reqId: 'foo', msg: 'some log message 2' },
87
+ { reqId: 'foo', msg: 'request completed' }
88
+ ]
89
+ t.plan(matches.length + 4)
90
+
91
+ const stream = split(JSON.parse)
92
+ const fastify = Fastify({
93
+ logger: { stream, level: 'info' },
94
+ requestIdHeader: 'my-custom-request-id',
95
+ genReqId (req) {
96
+ return 'foo'
97
+ }
98
+ })
99
+ t.after(() => fastify.close())
100
+
101
+ fastify.get('/one', (req, reply) => {
102
+ t.assert.strictEqual(req.id, REQUEST_ID)
103
+ req.log.info('some log message')
104
+ reply.send({ id: req.id })
105
+ })
106
+
107
+ fastify.get('/two', (req, reply) => {
108
+ t.assert.strictEqual(req.id, 'foo')
109
+ req.log.info('some log message 2')
110
+ reply.send({ id: req.id })
111
+ })
112
+
113
+ {
114
+ const response = await fastify.inject({ method: 'GET', url: '/one', headers: { 'my-custom-request-id': REQUEST_ID } })
115
+ const body = await response.json()
116
+ t.assert.strictEqual(body.id, REQUEST_ID)
117
+ }
118
+
119
+ {
120
+ const response = await fastify.inject({ method: 'GET', url: '/two' })
121
+ const body = await response.json()
122
+ t.assert.strictEqual(body.id, 'foo')
123
+ }
124
+
125
+ for await (const [line] of on(stream, 'data')) {
126
+ t.assert.ok(partialDeepStrictEqual(line, matches.shift()))
127
+ if (matches.length === 0) break
128
+ }
129
+ })
130
+
131
+ await t.test('The request id header key can be ignored along with a custom id generator', async (t) => {
132
+ const REQUEST_ID = 'ignore-me'
133
+ const matches = [
134
+ { reqId: 'foo', msg: 'incoming request' },
135
+ { reqId: 'foo', msg: 'some log message' },
136
+ { reqId: 'foo', msg: 'request completed' },
137
+ { reqId: 'foo', msg: 'incoming request' },
138
+ { reqId: 'foo', msg: 'some log message 2' },
139
+ { reqId: 'foo', msg: 'request completed' }
140
+ ]
141
+ t.plan(matches.length + 4)
142
+
143
+ const stream = split(JSON.parse)
144
+ const fastify = Fastify({
145
+ logger: { stream, level: 'info' },
146
+ requestIdHeader: false,
147
+ genReqId (req) {
148
+ return 'foo'
149
+ }
150
+ })
151
+ t.after(() => fastify.close())
152
+
153
+ fastify.get('/one', (req, reply) => {
154
+ t.assert.strictEqual(req.id, 'foo')
155
+ req.log.info('some log message')
156
+ reply.send({ id: req.id })
157
+ })
158
+
159
+ fastify.get('/two', (req, reply) => {
160
+ t.assert.strictEqual(req.id, 'foo')
161
+ req.log.info('some log message 2')
162
+ reply.send({ id: req.id })
163
+ })
164
+
165
+ {
166
+ const response = await fastify.inject({ method: 'GET', url: '/one', headers: { 'request-id': REQUEST_ID } })
167
+ const body = await response.json()
168
+ t.assert.strictEqual(body.id, 'foo')
169
+ }
170
+
171
+ {
172
+ const response = await fastify.inject({ method: 'GET', url: '/two' })
173
+ const body = await response.json()
174
+ t.assert.strictEqual(body.id, 'foo')
175
+ }
176
+
177
+ for await (const [line] of on(stream, 'data')) {
178
+ t.assert.ok(partialDeepStrictEqual(line, matches.shift()))
179
+ if (matches.length === 0) break
180
+ }
181
+ })
182
+
183
+ await t.test('The request id log label can be changed', async (t) => {
184
+ const REQUEST_ID = '42'
185
+ const matches = [
186
+ { traceId: REQUEST_ID, msg: 'incoming request' },
187
+ { traceId: REQUEST_ID, msg: 'some log message' },
188
+ { traceId: REQUEST_ID, msg: 'request completed' }
189
+ ]
190
+ t.plan(matches.length + 2)
191
+
192
+ const stream = split(JSON.parse)
193
+ const fastify = Fastify({
194
+ logger: { stream, level: 'info' },
195
+ requestIdHeader: 'my-custom-request-id',
196
+ requestIdLogLabel: 'traceId'
197
+ })
198
+ t.after(() => fastify.close())
199
+
200
+ fastify.get('/one', (req, reply) => {
201
+ t.assert.strictEqual(req.id, REQUEST_ID)
202
+ req.log.info('some log message')
203
+ reply.send({ id: req.id })
204
+ })
205
+
206
+ {
207
+ const response = await fastify.inject({ method: 'GET', url: '/one', headers: { 'my-custom-request-id': REQUEST_ID } })
208
+ const body = await response.json()
209
+ t.assert.strictEqual(body.id, REQUEST_ID)
210
+ }
211
+
212
+ for await (const [line] of on(stream, 'data')) {
213
+ t.assert.ok(partialDeepStrictEqual(line, matches.shift()))
214
+ if (matches.length === 0) break
215
+ }
216
+ })
217
+
218
+ await t.test('should redact the authorization header if so specified', async (t) => {
219
+ const stream = split(JSON.parse)
220
+ const fastify = Fastify({
221
+ logger: {
222
+ stream,
223
+ redact: ['req.headers.authorization'],
224
+ level: 'info',
225
+ serializers: {
226
+ req (req) {
227
+ return {
228
+ method: req.method,
229
+ url: req.url,
230
+ headers: req.headers,
231
+ hostname: req.hostname,
232
+ remoteAddress: req.ip,
233
+ remotePort: req.socket.remotePort
234
+ }
235
+ }
236
+ }
237
+ }
238
+ })
239
+ t.after(() => fastify.close())
240
+
241
+ fastify.get('/', function (req, reply) {
242
+ t.assert.deepStrictEqual(req.headers.authorization, 'Bearer abcde')
243
+ reply.send({ hello: 'world' })
244
+ })
245
+
246
+ await fastify.ready()
247
+ const server = await fastify.listen({ port: 0, host: localhost })
248
+
249
+ const lines = [
250
+ { msg: `Server listening at ${server}` },
251
+ { req: { headers: { authorization: '[Redacted]' } }, msg: 'incoming request' },
252
+ { res: { statusCode: 200 }, msg: 'request completed' }
253
+ ]
254
+ t.plan(lines.length + 3)
255
+
256
+ await request({
257
+ method: 'GET',
258
+ path: '/',
259
+ host: localhost,
260
+ port: fastify.server.address().port,
261
+ headers: {
262
+ authorization: 'Bearer abcde'
263
+ }
264
+ }, function (response, body) {
265
+ t.assert.strictEqual(response.statusCode, 200)
266
+ t.assert.deepStrictEqual(body, JSON.stringify({ hello: 'world' }))
267
+ })
268
+
269
+ for await (const [line] of on(stream, 'data')) {
270
+ t.assert.ok(partialDeepStrictEqual(line, lines.shift()))
271
+ if (lines.length === 0) break
272
+ }
273
+ })
274
+
275
+ await t.test('should not throw error when serializing custom req', (t) => {
276
+ t.plan(1)
277
+
278
+ const lines = []
279
+ const dest = new stream.Writable({
280
+ write: function (chunk, enc, cb) {
281
+ lines.push(JSON.parse(chunk))
282
+ cb()
283
+ }
284
+ })
285
+ const fastify = Fastify({ logger: { level: 'info', stream: dest } })
286
+ t.after(() => fastify.close())
287
+
288
+ fastify.log.info({ req: {} })
289
+
290
+ t.assert.deepStrictEqual(lines[0].req, {})
291
+ })
292
+ })
@@ -0,0 +1,183 @@
1
+ 'use strict'
2
+
3
+ const stream = require('node:stream')
4
+
5
+ const t = require('node:test')
6
+ const split = require('split2')
7
+ const pino = require('pino')
8
+
9
+ const Fastify = require('../../fastify')
10
+ const { partialDeepStrictEqual } = require('../toolkit')
11
+ const { on } = stream
12
+
13
+ t.test('response serialization', { timeout: 60000 }, async (t) => {
14
+ t.plan(4)
15
+
16
+ await t.test('Should use serializers from plugin and route', async (t) => {
17
+ const lines = [
18
+ { msg: 'incoming request' },
19
+ { test: 'XHello', test2: 'ZHello' },
20
+ { msg: 'request completed' }
21
+ ]
22
+ t.plan(lines.length + 1)
23
+
24
+ const stream = split(JSON.parse)
25
+
26
+ const loggerInstance = pino({ level: 'info' }, stream)
27
+ const fastify = Fastify({
28
+ loggerInstance
29
+ })
30
+ t.after(() => fastify.close())
31
+
32
+ fastify.register(context1, {
33
+ logSerializers: { test: value => 'X' + value }
34
+ })
35
+
36
+ function context1 (instance, opts, done) {
37
+ instance.get('/', {
38
+ logSerializers: {
39
+ test2: value => 'Z' + value
40
+ }
41
+ }, (req, reply) => {
42
+ req.log.info({ test: 'Hello', test2: 'Hello' }) // { test: 'XHello', test2: 'ZHello' }
43
+ reply.send({ hello: 'world' })
44
+ })
45
+ done()
46
+ }
47
+
48
+ await fastify.ready()
49
+
50
+ {
51
+ const response = await fastify.inject({ method: 'GET', url: '/' })
52
+ const body = await response.json()
53
+ t.assert.deepStrictEqual(body, { hello: 'world' })
54
+ }
55
+
56
+ for await (const [line] of on(stream, 'data')) {
57
+ t.assert.ok(partialDeepStrictEqual(line, lines.shift()))
58
+ if (lines.length === 0) break
59
+ }
60
+ })
61
+
62
+ await t.test('Should use serializers from instance fastify and route', async (t) => {
63
+ const lines = [
64
+ { msg: 'incoming request' },
65
+ { test: 'XHello', test2: 'ZHello' },
66
+ { msg: 'request completed' }
67
+ ]
68
+ t.plan(lines.length + 1)
69
+
70
+ const stream = split(JSON.parse)
71
+
72
+ const loggerInstance = pino({
73
+ level: 'info',
74
+ serializers: {
75
+ test: value => 'X' + value,
76
+ test2: value => 'This should be override - ' + value
77
+ }
78
+ }, stream)
79
+ const fastify = Fastify({
80
+ loggerInstance
81
+ })
82
+ t.after(() => fastify.close())
83
+
84
+ fastify.get('/', {
85
+ logSerializers: {
86
+ test2: value => 'Z' + value
87
+ }
88
+ }, (req, reply) => {
89
+ req.log.info({ test: 'Hello', test2: 'Hello' }) // { test: 'XHello', test2: 'ZHello' }
90
+ reply.send({ hello: 'world' })
91
+ })
92
+
93
+ await fastify.ready()
94
+
95
+ {
96
+ const response = await fastify.inject({ method: 'GET', url: '/' })
97
+ const body = await response.json()
98
+ t.assert.deepStrictEqual(body, { hello: 'world' })
99
+ }
100
+
101
+ for await (const [line] of on(stream, 'data')) {
102
+ t.assert.ok(partialDeepStrictEqual(line, lines.shift()))
103
+ if (lines.length === 0) break
104
+ }
105
+ })
106
+
107
+ await t.test('Should use serializers inherit from contexts', async (t) => {
108
+ const lines = [
109
+ { msg: 'incoming request' },
110
+ { test: 'XHello', test2: 'YHello', test3: 'ZHello' },
111
+ { msg: 'request completed' }
112
+ ]
113
+ t.plan(lines.length + 1)
114
+
115
+ const stream = split(JSON.parse)
116
+
117
+ const loggerInstance = pino({
118
+ level: 'info',
119
+ serializers: {
120
+ test: value => 'X' + value
121
+ }
122
+ }, stream)
123
+
124
+ const fastify = Fastify({ loggerInstance })
125
+ t.after(() => fastify.close())
126
+
127
+ fastify.register(context1, { logSerializers: { test2: value => 'Y' + value } })
128
+
129
+ function context1 (instance, opts, done) {
130
+ instance.get('/', {
131
+ logSerializers: {
132
+ test3: value => 'Z' + value
133
+ }
134
+ }, (req, reply) => {
135
+ req.log.info({ test: 'Hello', test2: 'Hello', test3: 'Hello' }) // { test: 'XHello', test2: 'YHello', test3: 'ZHello' }
136
+ reply.send({ hello: 'world' })
137
+ })
138
+ done()
139
+ }
140
+
141
+ await fastify.ready()
142
+
143
+ {
144
+ const response = await fastify.inject({ method: 'GET', url: '/' })
145
+ const body = await response.json()
146
+ t.assert.deepStrictEqual(body, { hello: 'world' })
147
+ }
148
+
149
+ for await (const [line] of on(stream, 'data')) {
150
+ t.assert.ok(partialDeepStrictEqual(line, lines.shift()))
151
+ if (lines.length === 0) break
152
+ }
153
+ })
154
+
155
+ await t.test('should serialize request and response', async (t) => {
156
+ const lines = [
157
+ { req: { method: 'GET', url: '/500' }, msg: 'incoming request' },
158
+ { req: { method: 'GET', url: '/500' }, msg: '500 error' },
159
+ { msg: 'request completed' }
160
+ ]
161
+ t.plan(lines.length + 1)
162
+
163
+ const stream = split(JSON.parse)
164
+ const fastify = Fastify({ logger: { level: 'info', stream } })
165
+ t.after(() => fastify.close())
166
+
167
+ fastify.get('/500', (req, reply) => {
168
+ reply.code(500).send(Error('500 error'))
169
+ })
170
+
171
+ await fastify.ready()
172
+
173
+ {
174
+ const response = await fastify.inject({ method: 'GET', url: '/500' })
175
+ t.assert.strictEqual(response.statusCode, 500)
176
+ }
177
+
178
+ for await (const [line] of on(stream, 'data')) {
179
+ t.assert.ok(partialDeepStrictEqual(line, lines.shift()))
180
+ if (lines.length === 0) break
181
+ }
182
+ })
183
+ })
File without changes
@@ -0,0 +1,113 @@
1
+ 'use strict'
2
+
3
+ const net = require('node:net')
4
+ const { test } = require('node:test')
5
+ const Fastify = require('..')
6
+
7
+ test('maxRequestsPerSocket', (t, done) => {
8
+ t.plan(8)
9
+
10
+ const fastify = Fastify({ maxRequestsPerSocket: 2 })
11
+ fastify.get('/', (req, reply) => {
12
+ reply.send({ hello: 'world' })
13
+ })
14
+
15
+ fastify.listen({ port: 0 }, function (err) {
16
+ t.assert.ifError(err)
17
+
18
+ const port = fastify.server.address().port
19
+ const client = net.createConnection({ port }, () => {
20
+ client.write('GET / HTTP/1.1\r\nHost: fastify.test\r\n\r\n')
21
+
22
+ client.once('data', data => {
23
+ t.assert.match(data.toString(), /Connection:\s*keep-alive/i)
24
+ t.assert.match(data.toString(), /Keep-Alive:\s*timeout=\d+/i)
25
+ t.assert.match(data.toString(), /200 OK/i)
26
+
27
+ client.write('GET / HTTP/1.1\r\nHost: fastify.test\r\n\r\n')
28
+
29
+ client.once('data', data => {
30
+ t.assert.match(data.toString(), /Connection:\s*close/i)
31
+ t.assert.match(data.toString(), /200 OK/i)
32
+
33
+ client.write('GET / HTTP/1.1\r\nHost: fastify.test\r\n\r\n')
34
+
35
+ client.once('data', data => {
36
+ t.assert.match(data.toString(), /Connection:\s*close/i)
37
+ t.assert.match(data.toString(), /503 Service Unavailable/i)
38
+ client.end()
39
+ fastify.close()
40
+ done()
41
+ })
42
+ })
43
+ })
44
+ })
45
+ })
46
+ })
47
+
48
+ test('maxRequestsPerSocket zero should behave same as null', (t, done) => {
49
+ t.plan(10)
50
+
51
+ const fastify = Fastify({ maxRequestsPerSocket: 0 })
52
+ fastify.get('/', (req, reply) => {
53
+ reply.send({ hello: 'world' })
54
+ })
55
+
56
+ fastify.listen({ port: 0 }, function (err) {
57
+ t.assert.ifError(err)
58
+
59
+ const port = fastify.server.address().port
60
+ const client = net.createConnection({ port }, () => {
61
+ client.write('GET / HTTP/1.1\r\nHost: fastify.test\r\n\r\n')
62
+
63
+ client.once('data', data => {
64
+ t.assert.match(data.toString(), /Connection:\s*keep-alive/i)
65
+ t.assert.match(data.toString(), /Keep-Alive:\s*timeout=\d+/i)
66
+ t.assert.match(data.toString(), /200 OK/i)
67
+
68
+ client.write('GET / HTTP/1.1\r\nHost: fastify.test\r\n\r\n')
69
+
70
+ client.once('data', data => {
71
+ t.assert.match(data.toString(), /Connection:\s*keep-alive/i)
72
+ t.assert.match(data.toString(), /Keep-Alive:\s*timeout=\d+/i)
73
+ t.assert.match(data.toString(), /200 OK/i)
74
+
75
+ client.write('GET / HTTP/1.1\r\nHost: fastify.test\r\n\r\n')
76
+
77
+ client.once('data', data => {
78
+ t.assert.match(data.toString(), /Connection:\s*keep-alive/i)
79
+ t.assert.match(data.toString(), /Keep-Alive:\s*timeout=\d+/i)
80
+ t.assert.match(data.toString(), /200 OK/i)
81
+ client.end()
82
+ fastify.close()
83
+ done()
84
+ })
85
+ })
86
+ })
87
+ })
88
+ })
89
+ })
90
+
91
+ test('maxRequestsPerSocket should be set', async (t) => {
92
+ t.plan(1)
93
+
94
+ const initialConfig = Fastify({ maxRequestsPerSocket: 5 }).initialConfig
95
+ t.assert.deepStrictEqual(initialConfig.maxRequestsPerSocket, 5)
96
+ })
97
+
98
+ test('maxRequestsPerSocket should 0', async (t) => {
99
+ t.plan(1)
100
+
101
+ const initialConfig = Fastify().initialConfig
102
+ t.assert.deepStrictEqual(initialConfig.maxRequestsPerSocket, 0)
103
+ })
104
+
105
+ test('requestTimeout passed to server', t => {
106
+ t.plan(2)
107
+
108
+ const httpServer = Fastify({ maxRequestsPerSocket: 5 }).server
109
+ t.assert.strictEqual(httpServer.maxRequestsPerSocket, 5)
110
+
111
+ const httpsServer = Fastify({ maxRequestsPerSocket: 5, https: true }).server
112
+ t.assert.strictEqual(httpsServer.maxRequestsPerSocket, 5)
113
+ })
@@ -0,0 +1,37 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('node:test')
4
+ const Fastify = require('..')
5
+ const {
6
+ FST_ERR_DEC_ALREADY_PRESENT
7
+ } = require('../lib/errors')
8
+
9
+ test('Should be able to override the default use API', t => {
10
+ t.plan(1)
11
+ const fastify = Fastify()
12
+ fastify.decorate('use', () => true)
13
+ t.assert.strictEqual(fastify.use(), true)
14
+ })
15
+
16
+ test('Cannot decorate use twice', t => {
17
+ t.plan(1)
18
+ const fastify = Fastify()
19
+ fastify.decorate('use', () => true)
20
+ try {
21
+ fastify.decorate('use', () => true)
22
+ } catch (err) {
23
+ t.assert.ok(err instanceof FST_ERR_DEC_ALREADY_PRESENT)
24
+ }
25
+ })
26
+
27
+ test('Encapsulation works', t => {
28
+ const fastify = Fastify()
29
+
30
+ fastify.register((instance, opts, done) => {
31
+ instance.decorate('use', () => true)
32
+ t.assert.strictEqual(instance.use(), true)
33
+ done()
34
+ })
35
+
36
+ fastify.ready()
37
+ })
@@ -0,0 +1,19 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('node:test')
4
+ const noopSet = require('../lib/noop-set')
5
+
6
+ test('does a lot of nothing', async t => {
7
+ const aSet = noopSet()
8
+ t.assert.ok(aSet, 'object')
9
+
10
+ const item = {}
11
+ aSet.add(item)
12
+ aSet.add({ another: 'item' })
13
+ aSet.delete(item)
14
+ t.assert.strictEqual(aSet.has(item), true)
15
+
16
+ for (const i of aSet) {
17
+ t.assert.fail('should not have any items: ' + i)
18
+ }
19
+ })