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,8 @@
1
+ // Imported in both index.test.js & esm.test.mjs
2
+ import { strictEqual } from 'node:assert'
3
+
4
+ async function other (fastify, opts) {
5
+ strictEqual(fastify.foo, 'bar')
6
+ }
7
+
8
+ export default other
@@ -0,0 +1,8 @@
1
+ // Imported in both index.test.js & esm.test.mjs
2
+ async function plugin (fastify, opts) {
3
+ fastify.decorate('foo', opts.foo)
4
+ }
5
+
6
+ plugin[Symbol.for('skip-override')] = true
7
+
8
+ export default plugin
@@ -0,0 +1,300 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('node:test')
4
+ const Fastify = require('..')
5
+ const os = require('node:os')
6
+
7
+ const {
8
+ kOptions,
9
+ kErrorHandler,
10
+ kChildLoggerFactory,
11
+ kState
12
+ } = require('../lib/symbols')
13
+
14
+ const isIPv6Missing = !Object.values(os.networkInterfaces()).flat().some(({ family }) => family === 'IPv6')
15
+
16
+ test('root fastify instance is an object', t => {
17
+ t.plan(1)
18
+ t.assert.strictEqual(typeof Fastify(), 'object')
19
+ })
20
+
21
+ test('fastify instance should contains ajv options', t => {
22
+ t.plan(1)
23
+ const fastify = Fastify({
24
+ ajv: {
25
+ customOptions: {
26
+ nullable: false
27
+ }
28
+ }
29
+ })
30
+ t.assert.deepStrictEqual(fastify[kOptions].ajv, {
31
+ customOptions: {
32
+ nullable: false
33
+ },
34
+ plugins: []
35
+ })
36
+ })
37
+
38
+ test('fastify instance should contains ajv options.plugins nested arrays', t => {
39
+ t.plan(1)
40
+ const fastify = Fastify({
41
+ ajv: {
42
+ customOptions: {
43
+ nullable: false
44
+ },
45
+ plugins: [[]]
46
+ }
47
+ })
48
+ t.assert.deepStrictEqual(fastify[kOptions].ajv, {
49
+ customOptions: {
50
+ nullable: false
51
+ },
52
+ plugins: [[]]
53
+ })
54
+ })
55
+
56
+ test('fastify instance get invalid ajv options', t => {
57
+ t.plan(1)
58
+ t.assert.throws(() => Fastify({
59
+ ajv: {
60
+ customOptions: 8
61
+ }
62
+ }))
63
+ })
64
+
65
+ test('fastify instance get invalid ajv options.plugins', t => {
66
+ t.plan(1)
67
+ t.assert.throws(() => Fastify({
68
+ ajv: {
69
+ customOptions: {},
70
+ plugins: 8
71
+ }
72
+ }))
73
+ })
74
+
75
+ test('fastify instance should contain default errorHandler', t => {
76
+ t.plan(3)
77
+ const fastify = Fastify()
78
+ t.assert.ok(fastify[kErrorHandler].func instanceof Function)
79
+ t.assert.deepStrictEqual(fastify.errorHandler, fastify[kErrorHandler].func)
80
+ t.assert.deepStrictEqual(Object.getOwnPropertyDescriptor(fastify, 'errorHandler').set, undefined)
81
+ })
82
+
83
+ test('errorHandler in plugin should be separate from the external one', async t => {
84
+ t.plan(4)
85
+ const fastify = Fastify()
86
+
87
+ fastify.register((instance, opts, done) => {
88
+ const inPluginErrHandler = (_, __, reply) => {
89
+ reply.send({ plugin: 'error-object' })
90
+ }
91
+
92
+ instance.setErrorHandler(inPluginErrHandler)
93
+
94
+ t.assert.notDeepStrictEqual(instance.errorHandler, fastify.errorHandler)
95
+ t.assert.strictEqual(instance.errorHandler.name, 'bound inPluginErrHandler')
96
+
97
+ done()
98
+ })
99
+
100
+ await fastify.ready()
101
+
102
+ t.assert.ok(fastify[kErrorHandler].func instanceof Function)
103
+ t.assert.deepStrictEqual(fastify.errorHandler, fastify[kErrorHandler].func)
104
+ })
105
+
106
+ test('fastify instance should contain default childLoggerFactory', t => {
107
+ t.plan(3)
108
+ const fastify = Fastify()
109
+ t.assert.ok(fastify[kChildLoggerFactory] instanceof Function)
110
+ t.assert.deepStrictEqual(fastify.childLoggerFactory, fastify[kChildLoggerFactory])
111
+ t.assert.deepStrictEqual(Object.getOwnPropertyDescriptor(fastify, 'childLoggerFactory').set, undefined)
112
+ })
113
+
114
+ test('childLoggerFactory in plugin should be separate from the external one', async t => {
115
+ t.plan(4)
116
+ const fastify = Fastify()
117
+
118
+ fastify.register((instance, opts, done) => {
119
+ const inPluginLoggerFactory = function (logger, bindings, opts) {
120
+ return logger.child(bindings, opts)
121
+ }
122
+
123
+ instance.setChildLoggerFactory(inPluginLoggerFactory)
124
+
125
+ t.assert.notDeepStrictEqual(instance.childLoggerFactory, fastify.childLoggerFactory)
126
+ t.assert.strictEqual(instance.childLoggerFactory.name, 'inPluginLoggerFactory')
127
+
128
+ done()
129
+ })
130
+
131
+ await fastify.ready()
132
+
133
+ t.assert.ok(fastify[kChildLoggerFactory] instanceof Function)
134
+ t.assert.deepStrictEqual(fastify.childLoggerFactory, fastify[kChildLoggerFactory])
135
+ })
136
+
137
+ test('ready should resolve in order when called multiply times (promises only)', async (t) => {
138
+ const app = Fastify()
139
+ const expectedOrder = [1, 2, 3, 4, 5]
140
+ const result = []
141
+
142
+ const promises = [1, 2, 3, 4, 5]
143
+ .map((id) => app.ready().then(() => result.push(id)))
144
+
145
+ await Promise.all(promises)
146
+
147
+ t.assert.deepStrictEqual(result, expectedOrder, 'Should resolve in order')
148
+ })
149
+
150
+ test('ready should reject in order when called multiply times (promises only)', async (t) => {
151
+ const app = Fastify()
152
+ const expectedOrder = [1, 2, 3, 4, 5]
153
+ const result = []
154
+
155
+ app.register((instance, opts, done) => {
156
+ setTimeout(() => done(new Error('test')), 500)
157
+ })
158
+
159
+ const promises = [1, 2, 3, 4, 5]
160
+ .map((id) => app.ready().catch(() => result.push(id)))
161
+
162
+ await Promise.all(promises)
163
+
164
+ t.assert.deepStrictEqual(result, expectedOrder, 'Should resolve in order')
165
+ })
166
+
167
+ test('ready should reject in order when called multiply times (callbacks only)', async (t) => {
168
+ const app = Fastify()
169
+ const expectedOrder = [1, 2, 3, 4, 5]
170
+ const result = []
171
+
172
+ app.register((instance, opts, done) => {
173
+ setTimeout(() => done(new Error('test')), 500)
174
+ })
175
+
176
+ expectedOrder.map((id) => app.ready(() => result.push(id)))
177
+
178
+ await app.ready().catch(err => {
179
+ t.assert.strictEqual(err.message, 'test')
180
+ })
181
+
182
+ t.assert.deepStrictEqual(result, expectedOrder, 'Should resolve in order')
183
+ })
184
+
185
+ test('ready should resolve in order when called multiply times (callbacks only)', async (t) => {
186
+ const app = Fastify()
187
+ const expectedOrder = [1, 2, 3, 4, 5]
188
+ const result = []
189
+
190
+ expectedOrder.map((id) => app.ready(() => result.push(id)))
191
+
192
+ await app.ready()
193
+
194
+ t.assert.deepStrictEqual(result, expectedOrder, 'Should resolve in order')
195
+ })
196
+
197
+ test('ready should resolve in order when called multiply times (mixed)', async (t) => {
198
+ const app = Fastify()
199
+ const expectedOrder = [1, 2, 3, 4, 5, 6]
200
+ const result = []
201
+
202
+ for (const order of expectedOrder) {
203
+ if (order % 2) {
204
+ app.ready(() => result.push(order))
205
+ } else {
206
+ app.ready().then(() => result.push(order))
207
+ }
208
+ }
209
+
210
+ await app.ready()
211
+
212
+ t.assert.deepStrictEqual(result, expectedOrder, 'Should resolve in order')
213
+ })
214
+
215
+ test('ready should reject in order when called multiply times (mixed)', async (t) => {
216
+ const app = Fastify()
217
+ const expectedOrder = [1, 2, 3, 4, 5, 6]
218
+ const result = []
219
+
220
+ app.register((instance, opts, done) => {
221
+ setTimeout(() => done(new Error('test')), 500)
222
+ })
223
+
224
+ for (const order of expectedOrder) {
225
+ if (order % 2) {
226
+ app.ready(() => result.push(order))
227
+ } else {
228
+ app.ready().then(null, () => result.push(order))
229
+ }
230
+ }
231
+
232
+ await app.ready().catch(err => {
233
+ t.assert.strictEqual(err.message, 'test')
234
+ })
235
+
236
+ t.assert.deepStrictEqual(result, expectedOrder, 'Should resolve in order')
237
+ })
238
+
239
+ test('ready should resolve in order when called multiply times (mixed)', async (t) => {
240
+ const app = Fastify()
241
+ const expectedOrder = [1, 2, 3, 4, 5, 6]
242
+ const result = []
243
+
244
+ for (const order of expectedOrder) {
245
+ if (order % 2) {
246
+ app.ready().then(() => result.push(order))
247
+ } else {
248
+ app.ready(() => result.push(order))
249
+ }
250
+ }
251
+
252
+ await app.ready()
253
+
254
+ t.assert.deepStrictEqual(result, expectedOrder, 'Should resolve in order')
255
+ })
256
+
257
+ test('fastify instance should contains listeningOrigin property (with port and host)', async t => {
258
+ t.plan(1)
259
+ const port = 3000
260
+ const host = '127.0.0.1'
261
+ const fastify = Fastify()
262
+ await fastify.listen({ port, host })
263
+ t.assert.deepStrictEqual(fastify.listeningOrigin, `http://${host}:${port}`)
264
+ await fastify.close()
265
+ })
266
+
267
+ test('fastify instance should contains listeningOrigin property (with port and https)', async t => {
268
+ t.plan(1)
269
+ const port = 3000
270
+ const host = '127.0.0.1'
271
+ const fastify = Fastify({ https: {} })
272
+ await fastify.listen({ port, host })
273
+ t.assert.deepStrictEqual(fastify.listeningOrigin, `https://${host}:${port}`)
274
+ await fastify.close()
275
+ })
276
+
277
+ test('fastify instance should contains listeningOrigin property (unix socket)', { skip: os.platform() === 'win32' }, async t => {
278
+ const fastify = Fastify()
279
+ const path = `fastify.${Date.now()}.sock`
280
+ await fastify.listen({ path })
281
+ t.assert.deepStrictEqual(fastify.listeningOrigin, path)
282
+ await fastify.close()
283
+ })
284
+
285
+ test('fastify instance should contains listeningOrigin property (IPv6)', { skip: isIPv6Missing }, async t => {
286
+ t.plan(1)
287
+ const port = 3000
288
+ const host = '::1'
289
+ const fastify = Fastify()
290
+ await fastify.listen({ port, host })
291
+ t.assert.deepStrictEqual(fastify.listeningOrigin, `http://[::1]:${port}`)
292
+ await fastify.close()
293
+ })
294
+
295
+ test('fastify instance should ensure ready promise cleanup on ready', async t => {
296
+ t.plan(1)
297
+ const fastify = Fastify()
298
+ await fastify.ready()
299
+ t.assert.strictEqual(fastify[kState].readyResolver, null)
300
+ })
@@ -0,0 +1,152 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('node:test')
4
+ const Fastify = require('..')
5
+ const fastifyPlugin = require('fastify-plugin')
6
+
7
+ test('findRoute should return null when route cannot be found due to a different method', t => {
8
+ t.plan(1)
9
+ const fastify = Fastify()
10
+
11
+ fastify.get('/artists/:artistId', {
12
+ schema: {
13
+ params: { artistId: { type: 'integer' } }
14
+ },
15
+ handler: (req, reply) => reply.send(typeof req.params.artistId)
16
+ })
17
+
18
+ t.assert.strictEqual(fastify.findRoute({
19
+ method: 'POST',
20
+ url: '/artists/:artistId'
21
+ }), null)
22
+ })
23
+
24
+ test('findRoute should return an immutable route to avoid leaking and runtime route modifications', t => {
25
+ t.plan(1)
26
+ const fastify = Fastify()
27
+
28
+ fastify.get('/artists/:artistId', {
29
+ schema: {
30
+ params: { artistId: { type: 'integer' } }
31
+ },
32
+ handler: (req, reply) => reply.send(typeof req.params.artistId)
33
+ })
34
+
35
+ let route = fastify.findRoute({
36
+ method: 'GET',
37
+ url: '/artists/:artistId'
38
+ })
39
+
40
+ route.params = {
41
+ ...route.params,
42
+ id: ':id'
43
+ }
44
+
45
+ route = fastify.findRoute({
46
+ method: 'GET',
47
+ url: '/artists/:artistId'
48
+ })
49
+
50
+ t.assert.strictEqual(route.params.artistId, ':artistId')
51
+ })
52
+
53
+ test('findRoute should return null when when url is not passed', t => {
54
+ t.plan(1)
55
+ const fastify = Fastify()
56
+
57
+ fastify.get('/artists/:artistId', {
58
+ schema: {
59
+ params: { artistId: { type: 'integer' } }
60
+ },
61
+ handler: (req, reply) => reply.send(typeof req.params.artistId)
62
+ })
63
+
64
+ t.assert.strictEqual(fastify.findRoute({
65
+ method: 'POST'
66
+ }), null)
67
+ })
68
+
69
+ test('findRoute should return null when route cannot be found due to a different path', t => {
70
+ t.plan(1)
71
+ const fastify = Fastify()
72
+
73
+ fastify.get('/artists/:artistId', {
74
+ schema: {
75
+ params: { artistId: { type: 'integer' } }
76
+ },
77
+ handler: (req, reply) => reply.send(typeof req.params.artistId)
78
+ })
79
+
80
+ t.assert.strictEqual(fastify.findRoute({
81
+ method: 'GET',
82
+ url: '/books/:bookId'
83
+ }), null)
84
+ })
85
+
86
+ test('findRoute should return the route when found', t => {
87
+ t.plan(1)
88
+ const fastify = Fastify()
89
+
90
+ const handler = (req, reply) => reply.send(typeof req.params.artistId)
91
+
92
+ fastify.get('/artists/:artistId', {
93
+ schema: {
94
+ params: { artistId: { type: 'integer' } }
95
+ },
96
+ handler
97
+ })
98
+
99
+ const route = fastify.findRoute({
100
+ method: 'GET',
101
+ url: '/artists/:artistId'
102
+ })
103
+ t.assert.strictEqual(route.params.artistId, ':artistId')
104
+ })
105
+
106
+ test('findRoute should work correctly when used within plugins', (t, done) => {
107
+ t.plan(1)
108
+ const fastify = Fastify()
109
+ const handler = (req, reply) => reply.send(typeof req.params.artistId)
110
+ fastify.get('/artists/:artistId', {
111
+ schema: {
112
+ params: { artistId: { type: 'integer' } }
113
+ },
114
+ handler
115
+ })
116
+
117
+ function validateRoutePlugin (instance, opts, done) {
118
+ const validateParams = function () {
119
+ return instance.findRoute({
120
+ method: 'GET',
121
+ url: '/artists/:artistId'
122
+ }) !== null
123
+ }
124
+ instance.decorate('validateRoutes', { validateParams })
125
+ done()
126
+ }
127
+
128
+ fastify.register(fastifyPlugin(validateRoutePlugin))
129
+
130
+ fastify.ready(() => {
131
+ t.assert.strictEqual(fastify.validateRoutes.validateParams(), true)
132
+ done()
133
+ })
134
+ })
135
+
136
+ test('findRoute should not expose store', t => {
137
+ t.plan(1)
138
+ const fastify = Fastify()
139
+
140
+ fastify.get('/artists/:artistId', {
141
+ schema: {
142
+ params: { artistId: { type: 'integer' } }
143
+ },
144
+ handler: (req, reply) => reply.send(typeof req.params.artistId)
145
+ })
146
+
147
+ const route = fastify.findRoute({
148
+ method: 'GET',
149
+ url: '/artists/:artistId'
150
+ })
151
+ t.assert.strictEqual(route.store, undefined)
152
+ })
@@ -0,0 +1,209 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('node:test')
4
+ const Fastify = require('..')
5
+ const S = require('fluent-json-schema')
6
+
7
+ test('use fluent-json-schema object', async (t) => {
8
+ t.plan(10)
9
+ const fastify = Fastify()
10
+
11
+ fastify.post('/:id', {
12
+ handler: (req, reply) => { reply.send({ name: 'a', surname: 'b', dateOfBirth: '01-01-2020' }) },
13
+ schema: {
14
+ params: S.object().prop('id', S.integer().minimum(42)),
15
+ headers: S.object().prop('x-custom', S.string().format('email')),
16
+ query: S.object().prop('surname', S.string().required()),
17
+ body: S.object().prop('name', S.string().required()),
18
+ response: {
19
+ 200: S.object()
20
+ .prop('name', S.string())
21
+ .prop('surname', S.string())
22
+ }
23
+ }
24
+ })
25
+
26
+ const res1 = await fastify.inject({
27
+ method: 'POST',
28
+ url: '/1',
29
+ headers: { 'x-custom': 'me@me.me' },
30
+ query: { surname: 'bar' },
31
+ payload: { name: 'foo' }
32
+ })
33
+ t.assert.strictEqual(res1.statusCode, 400)
34
+ t.assert.deepStrictEqual(res1.json(), { statusCode: 400, code: 'FST_ERR_VALIDATION', error: 'Bad Request', message: 'params/id must be >= 42' })
35
+
36
+ // check header
37
+ const res2 = await fastify.inject({
38
+ method: 'POST',
39
+ url: '/42',
40
+ headers: { 'x-custom': 'invalid' },
41
+ query: { surname: 'bar' },
42
+ payload: { name: 'foo' }
43
+ })
44
+ t.assert.strictEqual(res2.statusCode, 400)
45
+ t.assert.deepStrictEqual(res2.json(), { statusCode: 400, code: 'FST_ERR_VALIDATION', error: 'Bad Request', message: 'headers/x-custom must match format "email"' })
46
+
47
+ // check query
48
+ const res3 = await fastify.inject({
49
+ method: 'POST',
50
+ url: '/42',
51
+ headers: { 'x-custom': 'me@me.me' },
52
+ query: { },
53
+ payload: { name: 'foo' }
54
+ })
55
+ t.assert.strictEqual(res3.statusCode, 400)
56
+ t.assert.deepStrictEqual(res3.json(), { statusCode: 400, code: 'FST_ERR_VALIDATION', error: 'Bad Request', message: 'querystring must have required property \'surname\'' })
57
+
58
+ // check body
59
+ const res4 = await fastify.inject({
60
+ method: 'POST',
61
+ url: '/42',
62
+ headers: { 'x-custom': 'me@me.me' },
63
+ query: { surname: 'bar' },
64
+ payload: { name: [1, 2, 3] }
65
+ })
66
+ t.assert.strictEqual(res4.statusCode, 400)
67
+ t.assert.deepStrictEqual(res4.json(), { statusCode: 400, code: 'FST_ERR_VALIDATION', error: 'Bad Request', message: 'body/name must be string' })
68
+
69
+ // check response
70
+ const res5 = await fastify.inject({
71
+ method: 'POST',
72
+ url: '/42',
73
+ headers: { 'x-custom': 'me@me.me' },
74
+ query: { surname: 'bar' },
75
+ payload: { name: 'foo' }
76
+ })
77
+ t.assert.strictEqual(res5.statusCode, 200)
78
+ t.assert.deepStrictEqual(res5.json(), { name: 'a', surname: 'b' })
79
+ })
80
+
81
+ test('use complex fluent-json-schema object', (t, done) => {
82
+ t.plan(1)
83
+ const fastify = Fastify()
84
+
85
+ const addressSchema = S.object()
86
+ .id('#address')
87
+ .prop('line1').required()
88
+ .prop('line2')
89
+ .prop('country').required()
90
+ .prop('city').required()
91
+ .prop('zipcode').required()
92
+
93
+ const commonSchemas = S.object()
94
+ .id('https://fastify/demo')
95
+ .definition('addressSchema', addressSchema)
96
+
97
+ fastify.addSchema(commonSchemas)
98
+
99
+ const bodyJsonSchema = S.object()
100
+ .prop('residence', S.ref('https://fastify/demo#address')).required()
101
+ .prop('office', S.ref('https://fastify/demo#/definitions/addressSchema')).required()
102
+
103
+ fastify.post('/the/url', { schema: { body: bodyJsonSchema } }, () => { })
104
+ fastify.ready(err => {
105
+ t.assert.ifError(err)
106
+ done()
107
+ })
108
+ })
109
+
110
+ test('use fluent schema and plain JSON schema', (t, done) => {
111
+ t.plan(1)
112
+
113
+ const fastify = Fastify()
114
+
115
+ const addressSchema = S.object()
116
+ .id('#address')
117
+ .prop('line1').required()
118
+ .prop('line2')
119
+ .prop('country').required()
120
+ .prop('city').required()
121
+ .prop('zipcode').required()
122
+
123
+ const commonSchemas = S.object()
124
+ .id('https://fastify/demo')
125
+ .definition('addressSchema', addressSchema)
126
+
127
+ const sharedAddressSchema = {
128
+ $id: 'sharedAddress',
129
+ type: 'object',
130
+ required: ['line1', 'country', 'city', 'zipcode'],
131
+ properties: {
132
+ line1: { type: 'string' },
133
+ line2: { type: 'string' },
134
+ country: { type: 'string' },
135
+ city: { type: 'string' },
136
+ zipcode: { type: 'string' }
137
+ }
138
+ }
139
+
140
+ fastify.addSchema(commonSchemas)
141
+ fastify.addSchema(sharedAddressSchema)
142
+
143
+ const bodyJsonSchema = S.object()
144
+ .prop('residence', S.ref('https://fastify/demo#address')).required()
145
+ .prop('office', S.ref('https://fastify/demo#/definitions/addressSchema')).required()
146
+
147
+ fastify.post('/the/url', { schema: { body: bodyJsonSchema } }, () => { })
148
+ fastify.ready(err => {
149
+ t.assert.ifError(err)
150
+ done()
151
+ })
152
+ })
153
+
154
+ test('Should call valueOf internally', (t, done) => {
155
+ t.plan(1)
156
+
157
+ const fastify = new Fastify()
158
+
159
+ const addressSchema = S.object()
160
+ .id('#address')
161
+ .prop('line1').required()
162
+ .prop('line2')
163
+ .prop('country').required()
164
+ .prop('city').required()
165
+ .prop('zipcode').required()
166
+
167
+ const commonSchemas = S.object()
168
+ .id('https://fastify/demo')
169
+ .definition('addressSchema', addressSchema)
170
+
171
+ fastify.addSchema(commonSchemas)
172
+
173
+ fastify.route({
174
+ method: 'POST',
175
+ url: '/query',
176
+ handler: () => {},
177
+ schema: {
178
+ query: S.object().prop('hello', S.string()).required(),
179
+ body: S.object().prop('hello', S.string()).required(),
180
+ params: S.object().prop('hello', S.string()).required(),
181
+ headers: S.object().prop('hello', S.string()).required(),
182
+ response: {
183
+ 200: S.object().prop('hello', S.string()).required(),
184
+ 201: S.object().prop('hello', S.string()).required()
185
+ }
186
+ }
187
+ })
188
+
189
+ fastify.route({
190
+ method: 'POST',
191
+ url: '/querystring',
192
+ handler: () => {},
193
+ schema: {
194
+ querystring: S.object().prop('hello', S.string()).required(),
195
+ body: S.object().prop('hello', S.string()).required(),
196
+ params: S.object().prop('hello', S.string()).required(),
197
+ headers: S.object().prop('hello', S.string()).required(),
198
+ response: {
199
+ 200: S.object().prop('hello', S.string()).required(),
200
+ 201: S.object().prop('hello', S.string()).required()
201
+ }
202
+ }
203
+ })
204
+
205
+ fastify.ready(err => {
206
+ t.assert.ifError(err)
207
+ done()
208
+ })
209
+ })