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,359 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('node:test')
4
+ const Fastify = require('..')
5
+
6
+ test('Fastify should throw on wrong options', (t) => {
7
+ t.plan(2)
8
+ try {
9
+ Fastify('lol')
10
+ t.assert.fail()
11
+ } catch (e) {
12
+ t.assert.strictEqual(e.message, 'Options must be an object')
13
+ t.assert.ok(true)
14
+ }
15
+ })
16
+
17
+ test('Fastify should throw on multiple assignment to the same route', (t) => {
18
+ t.plan(1)
19
+ const fastify = Fastify()
20
+
21
+ fastify.get('/', () => {})
22
+
23
+ try {
24
+ fastify.get('/', () => {})
25
+ t.assert.fail('Should throw fastify duplicated route declaration')
26
+ } catch (error) {
27
+ t.assert.strictEqual(error.code, 'FST_ERR_DUPLICATED_ROUTE')
28
+ }
29
+ })
30
+
31
+ test('Fastify should throw for an invalid schema, printing the error route - headers', async (t) => {
32
+ t.plan(1)
33
+
34
+ const badSchema = {
35
+ type: 'object',
36
+ properties: {
37
+ bad: {
38
+ type: 'bad-type'
39
+ }
40
+ }
41
+ }
42
+ const fastify = Fastify()
43
+ fastify.get('/', { schema: { headers: badSchema } }, () => {})
44
+ fastify.get('/not-loaded', { schema: { headers: badSchema } }, () => {})
45
+
46
+ await t.assert.rejects(fastify.ready(), {
47
+ code: 'FST_ERR_SCH_VALIDATION_BUILD',
48
+ message: /Failed building the validation schema for GET: \//
49
+ })
50
+ })
51
+
52
+ test('Fastify should throw for an invalid schema, printing the error route - body', async (t) => {
53
+ t.plan(1)
54
+ const badSchema = {
55
+ type: 'object',
56
+ properties: {
57
+ bad: {
58
+ type: 'bad-type'
59
+ }
60
+ }
61
+ }
62
+
63
+ const fastify = Fastify()
64
+ fastify.register((instance, opts, done) => {
65
+ instance.post('/form', { schema: { body: badSchema } }, () => {})
66
+ done()
67
+ }, { prefix: 'hello' })
68
+
69
+ await t.assert.rejects(fastify.ready(), {
70
+ code: 'FST_ERR_SCH_VALIDATION_BUILD',
71
+ message: /Failed building the validation schema for POST: \/hello\/form/
72
+ })
73
+ })
74
+
75
+ test('Should throw on unsupported method', async (t) => {
76
+ t.plan(1)
77
+ const fastify = Fastify()
78
+ try {
79
+ fastify.route({
80
+ method: 'TROLL',
81
+ url: '/',
82
+ schema: {},
83
+ handler: function (req, reply) {}
84
+ })
85
+ t.assert.fail()
86
+ } catch (e) {
87
+ t.assert.ok(true)
88
+ }
89
+ })
90
+
91
+ test('Should throw on missing handler', (t) => {
92
+ t.plan(1)
93
+ const fastify = Fastify()
94
+ try {
95
+ fastify.route({
96
+ method: 'GET',
97
+ url: '/'
98
+ })
99
+ t.assert.fail()
100
+ } catch (e) {
101
+ t.assert.ok(true)
102
+ }
103
+ })
104
+
105
+ test('Should throw if one method is unsupported', async (t) => {
106
+ t.plan(1)
107
+ const fastify = Fastify()
108
+ try {
109
+ fastify.route({
110
+ method: ['GET', 'TROLL'],
111
+ url: '/',
112
+ schema: {},
113
+ handler: function (req, reply) {}
114
+ })
115
+ t.assert.fail()
116
+ } catch (e) {
117
+ t.assert.ok(true)
118
+ }
119
+ })
120
+
121
+ test('Should throw on duplicate content type parser', async (t) => {
122
+ t.plan(1)
123
+ const fastify = Fastify()
124
+ function customParser (req, payload, done) { done(null, '') }
125
+
126
+ fastify.addContentTypeParser('application/qq', customParser)
127
+ try {
128
+ fastify.addContentTypeParser('application/qq', customParser)
129
+ t.assert.fail()
130
+ } catch (e) {
131
+ t.assert.ok(true)
132
+ }
133
+ })
134
+
135
+ test('Should throw on duplicate decorator', async (t) => {
136
+ t.plan(1)
137
+
138
+ const fastify = Fastify()
139
+ const fooObj = {}
140
+
141
+ fastify.decorate('foo', fooObj)
142
+ try {
143
+ fastify.decorate('foo', fooObj)
144
+ t.assert.fail()
145
+ } catch (e) {
146
+ t.assert.ok(true)
147
+ }
148
+ })
149
+
150
+ test('Should not throw on duplicate decorator encapsulation', async (t) => {
151
+ t.plan(1)
152
+ const fastify = Fastify()
153
+ const foo2Obj = {}
154
+
155
+ fastify.decorate('foo2', foo2Obj)
156
+
157
+ fastify.register(function (fastify, opts, done) {
158
+ t.assert.doesNotThrow(() => {
159
+ fastify.decorate('foo2', foo2Obj)
160
+ })
161
+ done()
162
+ })
163
+
164
+ await fastify.ready()
165
+ })
166
+
167
+ test('Should throw on duplicate request decorator', async (t) => {
168
+ t.plan(2)
169
+
170
+ const fastify = Fastify()
171
+
172
+ fastify.decorateRequest('foo', null)
173
+ try {
174
+ fastify.decorateRequest('foo', null)
175
+ t.assert.fail()
176
+ } catch (e) {
177
+ t.assert.strictEqual(e.code, 'FST_ERR_DEC_ALREADY_PRESENT')
178
+ t.assert.strictEqual(e.message, 'The decorator \'foo\' has already been added!')
179
+ }
180
+ })
181
+
182
+ test('Should throw if request decorator dependencies are not met', async (t) => {
183
+ t.plan(2)
184
+
185
+ const fastify = Fastify()
186
+
187
+ try {
188
+ fastify.decorateRequest('bar', null, ['world'])
189
+ t.assert.fail()
190
+ } catch (e) {
191
+ t.assert.strictEqual(e.code, 'FST_ERR_DEC_MISSING_DEPENDENCY')
192
+ t.assert.strictEqual(e.message, 'The decorator is missing dependency \'world\'.')
193
+ }
194
+ })
195
+
196
+ test('Should throw on duplicate reply decorator', async (t) => {
197
+ t.plan(1)
198
+
199
+ const fastify = Fastify()
200
+
201
+ fastify.decorateReply('foo', null)
202
+ try {
203
+ fastify.decorateReply('foo', null)
204
+ t.assert.fail()
205
+ } catch (e) {
206
+ t.assert.ok(/has already been added/.test(e.message))
207
+ }
208
+ })
209
+
210
+ test('Should throw if reply decorator dependencies are not met', async (t) => {
211
+ t.plan(1)
212
+
213
+ const fastify = Fastify()
214
+
215
+ try {
216
+ fastify.decorateReply('bar', null, ['world'])
217
+ t.assert.fail()
218
+ } catch (e) {
219
+ t.assert.ok(/missing dependency/.test(e.message))
220
+ }
221
+ })
222
+
223
+ test('Should throw if handler as the third parameter to the shortcut method is missing and the second parameter is not a function and also not an object', async (t) => {
224
+ t.plan(5)
225
+
226
+ const fastify = Fastify()
227
+
228
+ try {
229
+ fastify.get('/foo/1', '')
230
+ t.assert.fail()
231
+ } catch (e) {
232
+ t.assert.ok(true)
233
+ }
234
+
235
+ try {
236
+ fastify.get('/foo/2', 1)
237
+ t.assert.fail()
238
+ } catch (e) {
239
+ t.assert.ok(true)
240
+ }
241
+
242
+ try {
243
+ fastify.get('/foo/3', [])
244
+ t.assert.fail()
245
+ } catch (e) {
246
+ t.assert.ok(true)
247
+ }
248
+
249
+ try {
250
+ fastify.get('/foo/4', undefined)
251
+ t.assert.fail()
252
+ } catch (e) {
253
+ t.assert.ok(true)
254
+ }
255
+
256
+ try {
257
+ fastify.get('/foo/5', null)
258
+ t.assert.fail()
259
+ } catch (e) {
260
+ t.assert.ok(true)
261
+ }
262
+ })
263
+
264
+ test('Should throw if handler as the third parameter to the shortcut method is missing and the second parameter is not a function and also not an object', async (t) => {
265
+ t.plan(5)
266
+
267
+ const fastify = Fastify()
268
+
269
+ try {
270
+ fastify.get('/foo/1', '')
271
+ t.assert.fail()
272
+ } catch (e) {
273
+ t.assert.ok(true)
274
+ }
275
+
276
+ try {
277
+ fastify.get('/foo/2', 1)
278
+ t.assert.fail()
279
+ } catch (e) {
280
+ t.assert.ok(true)
281
+ }
282
+
283
+ try {
284
+ fastify.get('/foo/3', [])
285
+ t.assert.fail()
286
+ } catch (e) {
287
+ t.assert.ok(true)
288
+ }
289
+
290
+ try {
291
+ fastify.get('/foo/4', undefined)
292
+ t.assert.fail()
293
+ } catch (e) {
294
+ t.assert.ok(true)
295
+ }
296
+
297
+ try {
298
+ fastify.get('/foo/5', null)
299
+ t.assert.fail()
300
+ } catch (e) {
301
+ t.assert.ok(true)
302
+ }
303
+ })
304
+
305
+ test('Should throw if there is handler function as the third parameter to the shortcut method and options as the second parameter is not an object', async (t) => {
306
+ t.plan(5)
307
+
308
+ const fastify = Fastify()
309
+
310
+ try {
311
+ fastify.get('/foo/1', '', (req, res) => {})
312
+ t.assert.fail()
313
+ } catch (e) {
314
+ t.assert.ok(true)
315
+ }
316
+
317
+ try {
318
+ fastify.get('/foo/2', 1, (req, res) => {})
319
+ t.assert.fail()
320
+ } catch (e) {
321
+ t.assert.ok(true)
322
+ }
323
+
324
+ try {
325
+ fastify.get('/foo/3', [], (req, res) => {})
326
+ t.assert.fail()
327
+ } catch (e) {
328
+ t.assert.ok(true)
329
+ }
330
+
331
+ try {
332
+ fastify.get('/foo/4', undefined, (req, res) => {})
333
+ t.assert.fail()
334
+ } catch (e) {
335
+ t.assert.ok(true)
336
+ }
337
+
338
+ try {
339
+ fastify.get('/foo/5', null, (req, res) => {})
340
+ t.assert.fail()
341
+ } catch (e) {
342
+ t.assert.ok(true)
343
+ }
344
+ })
345
+
346
+ test('Should throw if found duplicate handler as the third parameter to the shortcut method and in options', async (t) => {
347
+ t.plan(1)
348
+
349
+ const fastify = Fastify()
350
+
351
+ try {
352
+ fastify.get('/foo/abc', {
353
+ handler: (req, res) => {}
354
+ }, (req, res) => {})
355
+ t.assert.fail()
356
+ } catch (e) {
357
+ t.assert.ok(true)
358
+ }
359
+ })
@@ -0,0 +1,63 @@
1
+ 'use strict'
2
+
3
+ exports.waitForCb = function (options) {
4
+ let count = null
5
+ let done = false
6
+ let iResolve
7
+ let iReject
8
+
9
+ function stepIn () {
10
+ if (done) {
11
+ iReject(new Error('Unexpected done call'))
12
+ return
13
+ }
14
+
15
+ if (--count) {
16
+ return
17
+ }
18
+
19
+ done = true
20
+ iResolve()
21
+ }
22
+
23
+ const patience = new Promise((resolve, reject) => {
24
+ iResolve = resolve
25
+ iReject = reject
26
+ })
27
+
28
+ count = options.steps || 1
29
+ done = false
30
+
31
+ return { stepIn, patience }
32
+ }
33
+
34
+ exports.partialDeepStrictEqual = function partialDeepStrictEqual (actual, expected) {
35
+ if (typeof expected !== 'object' || expected === null) {
36
+ return actual === expected
37
+ }
38
+
39
+ if (typeof actual !== 'object' || actual === null) {
40
+ return false
41
+ }
42
+
43
+ if (Array.isArray(expected)) {
44
+ if (!Array.isArray(actual)) return false
45
+ if (expected.length > actual.length) return false
46
+
47
+ for (let i = 0; i < expected.length; i++) {
48
+ if (!partialDeepStrictEqual(actual[i], expected[i])) {
49
+ return false
50
+ }
51
+ }
52
+ return true
53
+ }
54
+
55
+ for (const key of Object.keys(expected)) {
56
+ if (!(key in actual)) return false
57
+ if (!partialDeepStrictEqual(actual[key], expected[key])) {
58
+ return false
59
+ }
60
+ }
61
+
62
+ return true
63
+ }
@@ -0,0 +1,162 @@
1
+ 'use strict'
2
+
3
+ const { test, before } = require('node:test')
4
+ const fastify = require('..')
5
+ const helper = require('./helper')
6
+
7
+ const fetchForwardedRequest = async (fastifyServer, forHeader, path, protoHeader) => {
8
+ const headers = {
9
+ 'X-Forwarded-For': forHeader,
10
+ 'X-Forwarded-Host': 'fastify.test'
11
+ }
12
+ if (protoHeader) {
13
+ headers['X-Forwarded-Proto'] = protoHeader
14
+ }
15
+
16
+ return fetch(fastifyServer + path, {
17
+ headers
18
+ })
19
+ }
20
+
21
+ const testRequestValues = (t, req, options) => {
22
+ if (options.ip) {
23
+ t.assert.ok(req.ip, 'ip is defined')
24
+ t.assert.strictEqual(req.ip, options.ip, 'gets ip from x-forwarded-for')
25
+ }
26
+ if (options.host) {
27
+ t.assert.ok(req.host, 'host is defined')
28
+ t.assert.strictEqual(req.host, options.host, 'gets host from x-forwarded-host')
29
+ t.assert.ok(req.hostname)
30
+ t.assert.strictEqual(req.hostname, options.host, 'gets hostname from x-forwarded-host')
31
+ }
32
+ if (options.ips) {
33
+ t.assert.deepStrictEqual(req.ips, options.ips, 'gets ips from x-forwarded-for')
34
+ }
35
+ if (options.protocol) {
36
+ t.assert.ok(req.protocol, 'protocol is defined')
37
+ t.assert.strictEqual(req.protocol, options.protocol, 'gets protocol from x-forwarded-proto')
38
+ }
39
+ if (options.port) {
40
+ t.assert.ok(req.port, 'port is defined')
41
+ t.assert.strictEqual(req.port, options.port, 'port is taken from x-forwarded-for or host')
42
+ }
43
+ }
44
+
45
+ let localhost
46
+ before(async function () {
47
+ [localhost] = await helper.getLoopbackHost()
48
+ })
49
+
50
+ test('trust proxy, not add properties to node req', async t => {
51
+ t.plan(13)
52
+ const app = fastify({
53
+ trustProxy: true
54
+ })
55
+ t.after(() => app.close())
56
+
57
+ app.get('/trustproxy', function (req, reply) {
58
+ testRequestValues(t, req, { ip: '1.1.1.1', host: 'fastify.test', port: app.server.address().port })
59
+ reply.code(200).send({ ip: req.ip, host: req.host })
60
+ })
61
+
62
+ app.get('/trustproxychain', function (req, reply) {
63
+ testRequestValues(t, req, { ip: '2.2.2.2', ips: [localhost, '1.1.1.1', '2.2.2.2'], port: app.server.address().port })
64
+ reply.code(200).send({ ip: req.ip, host: req.host })
65
+ })
66
+
67
+ const fastifyServer = await app.listen({ port: 0 })
68
+
69
+ await fetchForwardedRequest(fastifyServer, '1.1.1.1', '/trustproxy', undefined)
70
+ await fetchForwardedRequest(fastifyServer, '2.2.2.2, 1.1.1.1', '/trustproxychain', undefined)
71
+ })
72
+
73
+ test('trust proxy chain', async t => {
74
+ t.plan(8)
75
+ const app = fastify({
76
+ trustProxy: [localhost, '192.168.1.1']
77
+ })
78
+ t.after(() => app.close())
79
+
80
+ app.get('/trustproxychain', function (req, reply) {
81
+ testRequestValues(t, req, { ip: '1.1.1.1', host: 'fastify.test', port: app.server.address().port })
82
+ reply.code(200).send({ ip: req.ip, host: req.host })
83
+ })
84
+
85
+ const fastifyServer = await app.listen({ port: 0 })
86
+ await fetchForwardedRequest(fastifyServer, '192.168.1.1, 1.1.1.1', '/trustproxychain', undefined)
87
+ })
88
+
89
+ test('trust proxy function', async t => {
90
+ t.plan(8)
91
+ const app = fastify({
92
+ trustProxy: (address) => address === localhost
93
+ })
94
+ t.after(() => app.close())
95
+
96
+ app.get('/trustproxyfunc', function (req, reply) {
97
+ testRequestValues(t, req, { ip: '1.1.1.1', host: 'fastify.test', port: app.server.address().port })
98
+ reply.code(200).send({ ip: req.ip, host: req.host })
99
+ })
100
+
101
+ const fastifyServer = await app.listen({ port: 0 })
102
+ await fetchForwardedRequest(fastifyServer, '1.1.1.1', '/trustproxyfunc', undefined)
103
+ })
104
+
105
+ test('trust proxy number', async t => {
106
+ t.plan(9)
107
+ const app = fastify({
108
+ trustProxy: 1
109
+ })
110
+ t.after(() => app.close())
111
+
112
+ app.get('/trustproxynumber', function (req, reply) {
113
+ testRequestValues(t, req, { ip: '1.1.1.1', ips: [localhost, '1.1.1.1'], host: 'fastify.test', port: app.server.address().port })
114
+ reply.code(200).send({ ip: req.ip, host: req.host })
115
+ })
116
+
117
+ const fastifyServer = await app.listen({ port: 0 })
118
+ await fetchForwardedRequest(fastifyServer, '2.2.2.2, 1.1.1.1', '/trustproxynumber', undefined)
119
+ })
120
+
121
+ test('trust proxy IP addresses', async t => {
122
+ t.plan(9)
123
+ const app = fastify({
124
+ trustProxy: `${localhost}, 2.2.2.2`
125
+ })
126
+ t.after(() => app.close())
127
+
128
+ app.get('/trustproxyipaddrs', function (req, reply) {
129
+ testRequestValues(t, req, { ip: '1.1.1.1', ips: [localhost, '1.1.1.1'], host: 'fastify.test', port: app.server.address().port })
130
+ reply.code(200).send({ ip: req.ip, host: req.host })
131
+ })
132
+
133
+ const fastifyServer = await app.listen({ port: 0 })
134
+ await fetchForwardedRequest(fastifyServer, '3.3.3.3, 2.2.2.2, 1.1.1.1', '/trustproxyipaddrs', undefined)
135
+ })
136
+
137
+ test('trust proxy protocol', async t => {
138
+ t.plan(30)
139
+ const app = fastify({
140
+ trustProxy: true
141
+ })
142
+ t.after(() => app.close())
143
+
144
+ app.get('/trustproxyprotocol', function (req, reply) {
145
+ testRequestValues(t, req, { ip: '1.1.1.1', protocol: 'lorem', host: 'fastify.test', port: app.server.address().port })
146
+ reply.code(200).send({ ip: req.ip, host: req.host })
147
+ })
148
+ app.get('/trustproxynoprotocol', function (req, reply) {
149
+ testRequestValues(t, req, { ip: '1.1.1.1', protocol: 'http', host: 'fastify.test', port: app.server.address().port })
150
+ reply.code(200).send({ ip: req.ip, host: req.host })
151
+ })
152
+ app.get('/trustproxyprotocols', function (req, reply) {
153
+ testRequestValues(t, req, { ip: '1.1.1.1', protocol: 'dolor', host: 'fastify.test', port: app.server.address().port })
154
+ reply.code(200).send({ ip: req.ip, host: req.host })
155
+ })
156
+
157
+ const fastifyServer = await app.listen({ port: 0 })
158
+
159
+ await fetchForwardedRequest(fastifyServer, '1.1.1.1', '/trustproxyprotocol', 'lorem')
160
+ await fetchForwardedRequest(fastifyServer, '1.1.1.1', '/trustproxynoprotocol', undefined)
161
+ await fetchForwardedRequest(fastifyServer, '1.1.1.1', '/trustproxyprotocols', 'ipsum, dolor')
162
+ })
@@ -0,0 +1,22 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('node:test')
4
+ const Fastify = require('..')
5
+
6
+ test('Should export withTypeProvider function', (t, done) => {
7
+ t.plan(1)
8
+ try {
9
+ Fastify().withTypeProvider()
10
+ t.assert.ok('pass')
11
+ done()
12
+ } catch (e) {
13
+ t.assert.fail(e)
14
+ }
15
+ })
16
+
17
+ test('Should return same instance', (t, done) => {
18
+ t.plan(1)
19
+ const fastify = Fastify()
20
+ t.assert.strictEqual(fastify, fastify.withTypeProvider())
21
+ done()
22
+ })
@@ -0,0 +1,72 @@
1
+ import fastify, { FastifyBodyParser } from '../../fastify'
2
+ import { expectError, expectType } from 'tsd'
3
+ import { IncomingMessage } from 'node:http'
4
+ import { FastifyRequest } from '../../types/request'
5
+
6
+ expectType<void>(fastify().addContentTypeParser('contentType', function (request, payload, done) {
7
+ expectType<FastifyRequest>(request)
8
+ expectType<IncomingMessage>(payload)
9
+ done(null)
10
+ }))
11
+
12
+ // Body limit options
13
+
14
+ expectType<void>(fastify().addContentTypeParser('contentType', { bodyLimit: 99 }, function (request, payload, done) {
15
+ expectType<FastifyRequest>(request)
16
+ expectType<IncomingMessage>(payload)
17
+ done(null)
18
+ }))
19
+
20
+ // Array for contentType
21
+
22
+ expectType<void>(fastify().addContentTypeParser(['contentType'], function (request, payload, done) {
23
+ expectType<FastifyRequest>(request)
24
+ expectType<IncomingMessage>(payload)
25
+ done(null)
26
+ }))
27
+
28
+ // Body Parser - the generic after addContentTypeParser enforces the type of the `body` parameter as well as the value of the `parseAs` property
29
+
30
+ expectType<void>(fastify().addContentTypeParser<string>('bodyContentType', { parseAs: 'string' }, function (request, body, done) {
31
+ expectType<FastifyRequest>(request)
32
+ expectType<string>(body)
33
+ done(null)
34
+ }))
35
+
36
+ expectType<void>(fastify().addContentTypeParser<Buffer>('bodyContentType', { parseAs: 'buffer' }, function (request, body, done) {
37
+ expectType<FastifyRequest>(request)
38
+ expectType<Buffer>(body)
39
+ done(null)
40
+ }))
41
+
42
+ expectType<void>(fastify().addContentTypeParser('contentType', async function (request: FastifyRequest, payload: IncomingMessage) {
43
+ expectType<FastifyRequest>(request)
44
+ expectType<IncomingMessage>(payload)
45
+ return null
46
+ }))
47
+
48
+ expectType<void>(fastify().addContentTypeParser<string>('bodyContentType', { parseAs: 'string' }, async function (request: FastifyRequest, body: string) {
49
+ expectType<FastifyRequest>(request)
50
+ expectType<string>(body)
51
+ return null
52
+ }))
53
+
54
+ expectType<void>(fastify().addContentTypeParser<Buffer>('bodyContentType', { parseAs: 'buffer' }, async function (request: FastifyRequest, body: Buffer) {
55
+ expectType<FastifyRequest>(request)
56
+ expectType<Buffer>(body)
57
+ return null
58
+ }))
59
+
60
+ expectType<FastifyBodyParser<string>>(fastify().getDefaultJsonParser('error', 'ignore'))
61
+
62
+ expectError(fastify().getDefaultJsonParser('error', 'skip'))
63
+
64
+ expectError(fastify().getDefaultJsonParser('nothing', 'ignore'))
65
+
66
+ expectType<void>(fastify().removeAllContentTypeParsers())
67
+ expectError(fastify().removeAllContentTypeParsers('contentType'))
68
+
69
+ expectType<void>(fastify().removeContentTypeParser('contentType'))
70
+ expectType<void>(fastify().removeContentTypeParser(/contentType+.*/))
71
+ expectType<void>(fastify().removeContentTypeParser(['contentType', /contentType+.*/]))
72
+ expectError(fastify().removeContentTypeParser({}))
@@ -0,0 +1,18 @@
1
+ import fastify from '../../fastify'
2
+ import { expectType } from 'tsd'
3
+
4
+ type TestType = void
5
+
6
+ declare module '../../fastify' {
7
+ interface FastifyRequest {
8
+ testProp: TestType;
9
+ }
10
+ interface FastifyReply {
11
+ testProp: TestType;
12
+ }
13
+ }
14
+
15
+ fastify().get('/', (req, res) => {
16
+ expectType<TestType>(req.testProp)
17
+ expectType<TestType>(res.testProp)
18
+ })
@@ -0,0 +1,9 @@
1
+ import { FastifyPluginAsync } from '../../fastify'
2
+
3
+ export interface DummyPluginOptions {
4
+ foo?: number
5
+ }
6
+
7
+ declare const DummyPlugin: FastifyPluginAsync<DummyPluginOptions>
8
+
9
+ export default DummyPlugin