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,1330 @@
1
+ 'use strict'
2
+
3
+ const { test, describe } = require('node:test')
4
+ const Fastify = require('..')
5
+ const fp = require('fastify-plugin')
6
+ const symbols = require('../lib/symbols.js')
7
+
8
+ test('server methods should exist', t => {
9
+ t.plan(2)
10
+ const fastify = Fastify()
11
+ t.assert.ok(fastify.decorate)
12
+ t.assert.ok(fastify.hasDecorator)
13
+ })
14
+
15
+ test('should check if the given decoration already exist when null', (t, done) => {
16
+ t.plan(1)
17
+ const fastify = Fastify()
18
+ fastify.decorate('null', null)
19
+ fastify.ready(() => {
20
+ t.assert.ok(fastify.hasDecorator('null'))
21
+ done()
22
+ })
23
+ })
24
+
25
+ test('server methods should be encapsulated via .register', (t, done) => {
26
+ t.plan(2)
27
+ const fastify = Fastify()
28
+
29
+ fastify.register((instance, opts, done) => {
30
+ instance.decorate('test', () => {})
31
+ t.assert.ok(instance.test)
32
+ done()
33
+ })
34
+
35
+ fastify.ready(() => {
36
+ t.assert.strictEqual(fastify.test, undefined)
37
+ done()
38
+ })
39
+ })
40
+
41
+ test('hasServerMethod should check if the given method already exist', (t, done) => {
42
+ t.plan(2)
43
+ const fastify = Fastify()
44
+
45
+ fastify.register((instance, opts, done) => {
46
+ instance.decorate('test', () => {})
47
+ t.assert.ok(instance.hasDecorator('test'))
48
+ done()
49
+ })
50
+
51
+ fastify.ready(() => {
52
+ t.assert.strictEqual(fastify.hasDecorator('test'), false)
53
+ done()
54
+ })
55
+ })
56
+
57
+ test('decorate should throw if a declared dependency is not present', (t, done) => {
58
+ t.plan(3)
59
+ const fastify = Fastify()
60
+
61
+ fastify.register((instance, opts, done) => {
62
+ try {
63
+ instance.decorate('test', () => {}, ['dependency'])
64
+ t.assert.fail()
65
+ } catch (e) {
66
+ t.assert.strictEqual(e.code, 'FST_ERR_DEC_MISSING_DEPENDENCY')
67
+ t.assert.strictEqual(e.message, 'The decorator is missing dependency \'dependency\'.')
68
+ }
69
+ done()
70
+ })
71
+
72
+ fastify.ready(() => {
73
+ t.assert.ok('ready')
74
+ done()
75
+ })
76
+ })
77
+
78
+ test('decorate should throw if declared dependency is not array', (t, done) => {
79
+ t.plan(3)
80
+ const fastify = Fastify()
81
+
82
+ fastify.register((instance, opts, done) => {
83
+ try {
84
+ instance.decorate('test', () => {}, {})
85
+ t.assert.fail()
86
+ } catch (e) {
87
+ t.assert.strictEqual(e.code, 'FST_ERR_DEC_DEPENDENCY_INVALID_TYPE')
88
+ t.assert.strictEqual(e.message, 'The dependencies of decorator \'test\' must be of type Array.')
89
+ }
90
+ done()
91
+ })
92
+
93
+ fastify.ready(() => {
94
+ t.assert.ok('ready')
95
+ done()
96
+ })
97
+ })
98
+
99
+ // issue #777
100
+ test('should pass error for missing request decorator', (t, done) => {
101
+ t.plan(2)
102
+ const fastify = Fastify()
103
+
104
+ const plugin = fp(function (instance, opts, done) {
105
+ done()
106
+ }, {
107
+ decorators: {
108
+ request: ['foo']
109
+ }
110
+ })
111
+ fastify
112
+ .register(plugin)
113
+ .ready((err) => {
114
+ t.assert.ok(err instanceof Error)
115
+ t.assert.ok(err.message.includes("'foo'"))
116
+ done()
117
+ })
118
+ })
119
+
120
+ const runTests = async (t, fastifyServer) => {
121
+ const endpoints = [
122
+ { path: '/yes', expectedBody: { hello: 'world' } },
123
+ { path: '/no', expectedBody: { hello: 'world' } }
124
+ ]
125
+
126
+ for (const { path, expectedBody } of endpoints) {
127
+ const result = await fetch(`${fastifyServer}${path}`)
128
+ t.assert.ok(result.ok)
129
+ t.assert.strictEqual(result.status, 200)
130
+ const body = await result.text()
131
+ t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
132
+ t.assert.deepStrictEqual(JSON.parse(body), expectedBody)
133
+ }
134
+ }
135
+
136
+ test('decorateReply inside register', async (t) => {
137
+ t.plan(10)
138
+ const fastify = Fastify()
139
+
140
+ fastify.register((instance, opts, done) => {
141
+ instance.decorateReply('test', 'test')
142
+
143
+ instance.get('/yes', (req, reply) => {
144
+ t.assert.ok(reply.test, 'test exists')
145
+ reply.send({ hello: 'world' })
146
+ })
147
+
148
+ done()
149
+ })
150
+
151
+ fastify.get('/no', (req, reply) => {
152
+ t.assert.ok(!reply.test)
153
+ reply.send({ hello: 'world' })
154
+ })
155
+
156
+ const fastifyServer = await fastify.listen({ port: 0 })
157
+ t.after(() => fastify.close())
158
+
159
+ await runTests(t, fastifyServer)
160
+ })
161
+
162
+ test('decorateReply as plugin (inside .after)', async t => {
163
+ t.plan(10)
164
+ const fastify = Fastify()
165
+
166
+ fastify.register((instance, opts, done) => {
167
+ instance.register(fp((i, o, n) => {
168
+ instance.decorateReply('test', 'test')
169
+ n()
170
+ })).after(() => {
171
+ instance.get('/yes', (req, reply) => {
172
+ t.assert.ok(reply.test)
173
+ reply.send({ hello: 'world' })
174
+ })
175
+ })
176
+ done()
177
+ })
178
+
179
+ fastify.get('/no', (req, reply) => {
180
+ t.assert.ok(!reply.test)
181
+ reply.send({ hello: 'world' })
182
+ })
183
+
184
+ const fastifyServer = await fastify.listen({ port: 0 })
185
+ t.after(() => fastify.close())
186
+
187
+ await runTests(t, fastifyServer)
188
+ })
189
+
190
+ test('decorateReply as plugin (outside .after)', async t => {
191
+ t.plan(10)
192
+ const fastify = Fastify()
193
+
194
+ fastify.register((instance, opts, done) => {
195
+ instance.register(fp((i, o, n) => {
196
+ instance.decorateReply('test', 'test')
197
+ n()
198
+ }))
199
+
200
+ instance.get('/yes', (req, reply) => {
201
+ t.assert.ok(reply.test)
202
+ reply.send({ hello: 'world' })
203
+ })
204
+ done()
205
+ })
206
+
207
+ fastify.get('/no', (req, reply) => {
208
+ t.assert.ok(!reply.test)
209
+ reply.send({ hello: 'world' })
210
+ })
211
+
212
+ const fastifyServer = await fastify.listen({ port: 0 })
213
+ t.after(() => fastify.close())
214
+
215
+ await runTests(t, fastifyServer)
216
+ })
217
+
218
+ test('decorateRequest inside register', async t => {
219
+ t.plan(10)
220
+ const fastify = Fastify()
221
+
222
+ fastify.register((instance, opts, done) => {
223
+ instance.decorateRequest('test', 'test')
224
+
225
+ instance.get('/yes', (req, reply) => {
226
+ t.assert.ok(req.test, 'test exists')
227
+ reply.send({ hello: 'world' })
228
+ })
229
+
230
+ done()
231
+ })
232
+
233
+ fastify.get('/no', (req, reply) => {
234
+ t.assert.ok(!req.test)
235
+ reply.send({ hello: 'world' })
236
+ })
237
+
238
+ const fastifyServer = await fastify.listen({ port: 0 })
239
+ t.after(() => fastify.close())
240
+
241
+ await runTests(t, fastifyServer)
242
+ })
243
+
244
+ test('decorateRequest as plugin (inside .after)', async t => {
245
+ t.plan(10)
246
+ const fastify = Fastify()
247
+
248
+ fastify.register((instance, opts, done) => {
249
+ instance.register(fp((i, o, n) => {
250
+ instance.decorateRequest('test', 'test')
251
+ n()
252
+ })).after(() => {
253
+ instance.get('/yes', (req, reply) => {
254
+ t.assert.ok(req.test)
255
+ reply.send({ hello: 'world' })
256
+ })
257
+ })
258
+ done()
259
+ })
260
+
261
+ fastify.get('/no', (req, reply) => {
262
+ t.assert.ok(!req.test)
263
+ reply.send({ hello: 'world' })
264
+ })
265
+
266
+ const fastifyServer = await fastify.listen({ port: 0 })
267
+ t.after(() => fastify.close())
268
+
269
+ await runTests(t, fastifyServer)
270
+ })
271
+
272
+ test('decorateRequest as plugin (outside .after)', async (t) => {
273
+ t.plan(10)
274
+ const fastify = Fastify()
275
+
276
+ fastify.register((instance, opts, done) => {
277
+ instance.register(fp((i, o, n) => {
278
+ instance.decorateRequest('test', 'test')
279
+ n()
280
+ }))
281
+
282
+ instance.get('/yes', (req, reply) => {
283
+ t.assert.ok(req.test)
284
+ reply.send({ hello: 'world' })
285
+ })
286
+ done()
287
+ })
288
+
289
+ fastify.get('/no', (req, reply) => {
290
+ t.assert.ok(!req.test)
291
+ reply.send({ hello: 'world' })
292
+ })
293
+
294
+ const fastifyServer = await fastify.listen({ port: 0 })
295
+ t.after(() => fastify.close())
296
+
297
+ await runTests(t, fastifyServer)
298
+ })
299
+
300
+ test('decorators should be instance separated', (t, done) => {
301
+ t.plan(1)
302
+
303
+ const fastify1 = Fastify()
304
+ const fastify2 = Fastify()
305
+
306
+ fastify1.decorate('test', 'foo')
307
+ fastify2.decorate('test', 'foo')
308
+
309
+ fastify1.decorateRequest('test', 'foo')
310
+ fastify2.decorateRequest('test', 'foo')
311
+
312
+ fastify1.decorateReply('test', 'foo')
313
+ fastify2.decorateReply('test', 'foo')
314
+
315
+ t.assert.ok('Done')
316
+ done()
317
+ })
318
+
319
+ describe('hasRequestDecorator', () => {
320
+ const requestDecoratorName = 'my-decorator-name'
321
+
322
+ test('is a function', async t => {
323
+ const fastify = Fastify()
324
+ t.assert.ok(fastify.hasRequestDecorator)
325
+ })
326
+
327
+ test('should check if the given request decoration already exist', async t => {
328
+ const fastify = Fastify()
329
+
330
+ t.assert.ok(!fastify.hasRequestDecorator(requestDecoratorName))
331
+ fastify.decorateRequest(requestDecoratorName, 42)
332
+ t.assert.ok(fastify.hasRequestDecorator(requestDecoratorName))
333
+ })
334
+
335
+ test('should check if the given request decoration already exist when null', async t => {
336
+ const fastify = Fastify()
337
+
338
+ t.assert.ok(!fastify.hasRequestDecorator(requestDecoratorName))
339
+ fastify.decorateRequest(requestDecoratorName, null)
340
+ t.assert.ok(fastify.hasRequestDecorator(requestDecoratorName))
341
+ })
342
+
343
+ test('should be plugin encapsulable', async t => {
344
+ const fastify = Fastify()
345
+
346
+ t.assert.ok(!fastify.hasRequestDecorator(requestDecoratorName))
347
+
348
+ await fastify.register(async function (fastify2, opts) {
349
+ fastify2.decorateRequest(requestDecoratorName, 42)
350
+ t.assert.ok(fastify2.hasRequestDecorator(requestDecoratorName))
351
+ })
352
+
353
+ t.assert.ok(!fastify.hasRequestDecorator(requestDecoratorName))
354
+
355
+ await fastify.ready()
356
+ t.assert.ok(!fastify.hasRequestDecorator(requestDecoratorName))
357
+ })
358
+
359
+ test('should be inherited', async t => {
360
+ const fastify = Fastify()
361
+
362
+ fastify.decorateRequest(requestDecoratorName, 42)
363
+
364
+ await fastify.register(async function (fastify2, opts) {
365
+ t.assert.ok(fastify2.hasRequestDecorator(requestDecoratorName))
366
+ })
367
+
368
+ await fastify.ready()
369
+ t.assert.ok(fastify.hasRequestDecorator(requestDecoratorName))
370
+ })
371
+ })
372
+
373
+ describe('hasReplyDecorator', () => {
374
+ const replyDecoratorName = 'my-decorator-name'
375
+
376
+ test('is a function', async t => {
377
+ const fastify = Fastify()
378
+ t.assert.ok(fastify.hasReplyDecorator)
379
+ })
380
+
381
+ test('should check if the given reply decoration already exist', async t => {
382
+ const fastify = Fastify()
383
+
384
+ t.assert.ok(!fastify.hasReplyDecorator(replyDecoratorName))
385
+ fastify.decorateReply(replyDecoratorName, 42)
386
+ t.assert.ok(fastify.hasReplyDecorator(replyDecoratorName))
387
+ })
388
+
389
+ test('should check if the given reply decoration already exist when null', async t => {
390
+ const fastify = Fastify()
391
+
392
+ t.assert.ok(!fastify.hasReplyDecorator(replyDecoratorName))
393
+ fastify.decorateReply(replyDecoratorName, null)
394
+ t.assert.ok(fastify.hasReplyDecorator(replyDecoratorName))
395
+ })
396
+
397
+ test('should be plugin encapsulable', async t => {
398
+ const fastify = Fastify()
399
+
400
+ t.assert.ok(!fastify.hasReplyDecorator(replyDecoratorName))
401
+
402
+ await fastify.register(async function (fastify2, opts) {
403
+ fastify2.decorateReply(replyDecoratorName, 42)
404
+ t.assert.ok(fastify2.hasReplyDecorator(replyDecoratorName))
405
+ })
406
+
407
+ t.assert.ok(!fastify.hasReplyDecorator(replyDecoratorName))
408
+
409
+ await fastify.ready()
410
+ t.assert.ok(!fastify.hasReplyDecorator(replyDecoratorName))
411
+ })
412
+
413
+ test('should be inherited', async t => {
414
+ const fastify = Fastify()
415
+
416
+ fastify.decorateReply(replyDecoratorName, 42)
417
+
418
+ await fastify.register(async function (fastify2, opts) {
419
+ t.assert.ok(fastify2.hasReplyDecorator(replyDecoratorName))
420
+ })
421
+
422
+ await fastify.ready()
423
+ t.assert.ok(fastify.hasReplyDecorator(replyDecoratorName))
424
+ })
425
+ })
426
+
427
+ test('should register properties via getter/setter objects', (t, done) => {
428
+ t.plan(3)
429
+ const fastify = Fastify()
430
+
431
+ fastify.register((instance, opts, done) => {
432
+ instance.decorate('test', {
433
+ getter () {
434
+ return 'a getter'
435
+ }
436
+ })
437
+ t.assert.ok(instance.test)
438
+ t.assert.ok(instance.test, 'a getter')
439
+ done()
440
+ })
441
+
442
+ fastify.ready(() => {
443
+ t.assert.ok(!fastify.test)
444
+ done()
445
+ })
446
+ })
447
+
448
+ test('decorateRequest should work with getter/setter', (t, done) => {
449
+ t.plan(5)
450
+ const fastify = Fastify()
451
+
452
+ fastify.register((instance, opts, done) => {
453
+ instance.decorateRequest('test', {
454
+ getter () {
455
+ return 'a getter'
456
+ }
457
+ })
458
+
459
+ instance.get('/req-decorated-get-set', (req, res) => {
460
+ res.send({ test: req.test })
461
+ })
462
+
463
+ done()
464
+ })
465
+
466
+ fastify.get('/not-decorated', (req, res) => {
467
+ t.assert.ok(!req.test)
468
+ res.send()
469
+ })
470
+
471
+ let pending = 2
472
+
473
+ function completed () {
474
+ if (--pending === 0) {
475
+ done()
476
+ }
477
+ }
478
+
479
+ fastify.ready(() => {
480
+ fastify.inject({ url: '/req-decorated-get-set' }, (err, res) => {
481
+ t.assert.ifError(err)
482
+ t.assert.deepStrictEqual(JSON.parse(res.payload), { test: 'a getter' })
483
+ completed()
484
+ })
485
+
486
+ fastify.inject({ url: '/not-decorated' }, (err, res) => {
487
+ t.assert.ifError(err)
488
+ t.assert.ok('ok', 'not decorated')
489
+ completed()
490
+ })
491
+ })
492
+ })
493
+
494
+ test('decorateReply should work with getter/setter', (t, done) => {
495
+ t.plan(5)
496
+ const fastify = Fastify()
497
+
498
+ fastify.register((instance, opts, done) => {
499
+ instance.decorateReply('test', {
500
+ getter () {
501
+ return 'a getter'
502
+ }
503
+ })
504
+
505
+ instance.get('/res-decorated-get-set', (req, res) => {
506
+ res.send({ test: res.test })
507
+ })
508
+
509
+ done()
510
+ })
511
+
512
+ fastify.get('/not-decorated', (req, res) => {
513
+ t.assert.ok(!res.test)
514
+ res.send()
515
+ })
516
+
517
+ let pending = 2
518
+
519
+ function completed () {
520
+ if (--pending === 0) {
521
+ done()
522
+ }
523
+ }
524
+ fastify.ready(() => {
525
+ fastify.inject({ url: '/res-decorated-get-set' }, (err, res) => {
526
+ t.assert.ifError(err)
527
+ t.assert.deepStrictEqual(JSON.parse(res.payload), { test: 'a getter' })
528
+ completed()
529
+ })
530
+
531
+ fastify.inject({ url: '/not-decorated' }, (err, res) => {
532
+ t.assert.ifError(err)
533
+ t.assert.ok('ok')
534
+ completed()
535
+ })
536
+ })
537
+ })
538
+
539
+ test('should register empty values', (t, done) => {
540
+ t.plan(2)
541
+ const fastify = Fastify()
542
+
543
+ fastify.register((instance, opts, done) => {
544
+ instance.decorate('test', null)
545
+ t.assert.ok(Object.hasOwn(instance, 'test'))
546
+ done()
547
+ })
548
+
549
+ fastify.ready(() => {
550
+ t.assert.ok(!fastify.test)
551
+ done()
552
+ })
553
+ })
554
+
555
+ test('nested plugins can override things', (t, done) => {
556
+ t.plan(6)
557
+ const fastify = Fastify()
558
+
559
+ const rootFunc = () => {}
560
+ fastify.decorate('test', rootFunc)
561
+ fastify.decorateRequest('test', rootFunc)
562
+ fastify.decorateReply('test', rootFunc)
563
+
564
+ fastify.register((instance, opts, done) => {
565
+ const func = () => {}
566
+ instance.decorate('test', func)
567
+ instance.decorateRequest('test', func)
568
+ instance.decorateReply('test', func)
569
+
570
+ t.assert.strictEqual(instance.test, func)
571
+ t.assert.strictEqual(instance[symbols.kRequest].prototype.test, func)
572
+ t.assert.strictEqual(instance[symbols.kReply].prototype.test, func)
573
+ done()
574
+ })
575
+
576
+ fastify.ready(() => {
577
+ t.assert.strictEqual(fastify.test, rootFunc)
578
+ t.assert.strictEqual(fastify[symbols.kRequest].prototype.test, rootFunc)
579
+ t.assert.strictEqual(fastify[symbols.kReply].prototype.test, rootFunc)
580
+ done()
581
+ })
582
+ })
583
+
584
+ test('a decorator should addSchema to all the encapsulated tree', (t, done) => {
585
+ t.plan(1)
586
+ const fastify = Fastify()
587
+
588
+ const decorator = function (instance, opts, done) {
589
+ instance.decorate('decoratorAddSchema', function (whereAddTheSchema) {
590
+ instance.addSchema({
591
+ $id: 'schema',
592
+ type: 'string'
593
+ })
594
+ })
595
+ done()
596
+ }
597
+
598
+ fastify.register(fp(decorator))
599
+
600
+ fastify.register(function (instance, opts, done) {
601
+ instance.register((subInstance, opts, done) => {
602
+ subInstance.decoratorAddSchema()
603
+ done()
604
+ })
605
+ done()
606
+ })
607
+
608
+ fastify.ready(() => {
609
+ t.assert.ifError()
610
+ done()
611
+ })
612
+ })
613
+
614
+ test('after can access to a decorated instance and previous plugin decoration', (t, done) => {
615
+ t.plan(11)
616
+ const TEST_VALUE = {}
617
+ const OTHER_TEST_VALUE = {}
618
+ const NEW_TEST_VALUE = {}
619
+
620
+ const fastify = Fastify()
621
+
622
+ fastify.register(fp(function (instance, options, done) {
623
+ instance.decorate('test', TEST_VALUE)
624
+
625
+ done()
626
+ })).after(function (err, instance, done) {
627
+ t.assert.ifError(err)
628
+ t.assert.strictEqual(instance.test, TEST_VALUE)
629
+
630
+ instance.decorate('test2', OTHER_TEST_VALUE)
631
+ done()
632
+ })
633
+
634
+ fastify.register(fp(function (instance, options, done) {
635
+ t.assert.strictEqual(instance.test, TEST_VALUE)
636
+ t.assert.strictEqual(instance.test2, OTHER_TEST_VALUE)
637
+
638
+ instance.decorate('test3', NEW_TEST_VALUE)
639
+
640
+ done()
641
+ })).after(function (err, instance, done) {
642
+ t.assert.ifError(err)
643
+ t.assert.strictEqual(instance.test, TEST_VALUE)
644
+ t.assert.strictEqual(instance.test2, OTHER_TEST_VALUE)
645
+ t.assert.strictEqual(instance.test3, NEW_TEST_VALUE)
646
+
647
+ done()
648
+ })
649
+
650
+ fastify.get('/', function (req, res) {
651
+ t.assert.strictEqual(this.test, TEST_VALUE)
652
+ t.assert.strictEqual(this.test2, OTHER_TEST_VALUE)
653
+ res.send({})
654
+ })
655
+
656
+ fastify.inject('/')
657
+ .then(response => {
658
+ t.assert.strictEqual(response.statusCode, 200)
659
+ done()
660
+ })
661
+ })
662
+
663
+ test('decorate* should throw if called after ready', async t => {
664
+ t.plan(6)
665
+ const fastify = Fastify()
666
+
667
+ fastify.get('/', (request, reply) => {
668
+ reply.send({
669
+ hello: 'world'
670
+ })
671
+ })
672
+
673
+ await fastify.listen({ port: 0 })
674
+ try {
675
+ fastify.decorate('test', true)
676
+ t.assert.fail('should not decorate')
677
+ } catch (err) {
678
+ t.assert.strictEqual(err.code, 'FST_ERR_DEC_AFTER_START')
679
+ t.assert.strictEqual(err.message, "The decorator 'test' has been added after start!")
680
+ }
681
+ try {
682
+ fastify.decorateRequest('test', true)
683
+ t.assert.fail('should not decorate')
684
+ } catch (e) {
685
+ t.assert.strictEqual(e.code, 'FST_ERR_DEC_AFTER_START')
686
+ t.assert.strictEqual(e.message, "The decorator 'test' has been added after start!")
687
+ }
688
+ try {
689
+ fastify.decorateReply('test', true)
690
+ t.assert.fail('should not decorate')
691
+ } catch (e) {
692
+ t.assert.strictEqual(e.code, 'FST_ERR_DEC_AFTER_START')
693
+ t.assert.strictEqual(e.message, "The decorator 'test' has been added after start!")
694
+ }
695
+ await fastify.close()
696
+ })
697
+
698
+ test('decorate* should emit error if an array is passed', t => {
699
+ t.plan(2)
700
+
701
+ const fastify = Fastify()
702
+ try {
703
+ fastify.decorateRequest('test_array', [])
704
+ t.assert.fail('should not decorate')
705
+ } catch (err) {
706
+ t.assert.strictEqual(err.code, 'FST_ERR_DEC_REFERENCE_TYPE')
707
+ t.assert.strictEqual(err.message, "The decorator 'test_array' of type 'object' is a reference type. Use the { getter, setter } interface instead.")
708
+ }
709
+ })
710
+
711
+ test('server.decorate should not emit error if reference type is passed', async t => {
712
+ t.plan(1)
713
+
714
+ const fastify = Fastify()
715
+ fastify.decorate('test_array', [])
716
+ fastify.decorate('test_object', {})
717
+ await fastify.ready()
718
+ t.assert.ok('Done')
719
+ })
720
+
721
+ test('decorate* should emit warning if object type is passed', t => {
722
+ t.plan(2)
723
+
724
+ const fastify = Fastify()
725
+ try {
726
+ fastify.decorateRequest('test_object', { foo: 'bar' })
727
+ t.assert.fail('should not decorate')
728
+ } catch (err) {
729
+ t.assert.strictEqual(err.code, 'FST_ERR_DEC_REFERENCE_TYPE')
730
+ t.assert.strictEqual(err.message, "The decorator 'test_object' of type 'object' is a reference type. Use the { getter, setter } interface instead.")
731
+ }
732
+ })
733
+
734
+ test('decorate* should not emit warning if object with getter/setter is passed', t => {
735
+ const fastify = Fastify()
736
+
737
+ fastify.decorateRequest('test_getter_setter', {
738
+ setter (val) {
739
+ this._ = val
740
+ },
741
+ getter () {
742
+ return 'a getter'
743
+ }
744
+ })
745
+ t.assert.ok('Done')
746
+ })
747
+
748
+ test('decorateRequest with getter/setter can handle encapsulation', async t => {
749
+ t.plan(24)
750
+
751
+ const fastify = Fastify({ logger: true })
752
+
753
+ fastify.decorateRequest('test_getter_setter_holder')
754
+ fastify.decorateRequest('test_getter_setter', {
755
+ getter () {
756
+ this.test_getter_setter_holder ??= {}
757
+ return this.test_getter_setter_holder
758
+ }
759
+ })
760
+
761
+ fastify.get('/', async function (req, reply) {
762
+ t.assert.deepStrictEqual(req.test_getter_setter, {}, 'a getter')
763
+ req.test_getter_setter.a = req.id
764
+ t.assert.deepStrictEqual(req.test_getter_setter, { a: req.id })
765
+ })
766
+
767
+ fastify.addHook('onResponse', async function hook (req, reply) {
768
+ t.assert.deepStrictEqual(req.test_getter_setter, { a: req.id })
769
+ })
770
+
771
+ await Promise.all([
772
+ fastify.inject('/').then(res => t.assert.strictEqual(res.statusCode, 200)),
773
+ fastify.inject('/').then(res => t.assert.strictEqual(res.statusCode, 200)),
774
+ fastify.inject('/').then(res => t.assert.strictEqual(res.statusCode, 200)),
775
+ fastify.inject('/').then(res => t.assert.strictEqual(res.statusCode, 200)),
776
+ fastify.inject('/').then(res => t.assert.strictEqual(res.statusCode, 200)),
777
+ fastify.inject('/').then(res => t.assert.strictEqual(res.statusCode, 200))
778
+ ])
779
+ })
780
+
781
+ test('decorateRequest with getter/setter can handle encapsulation with arrays', async t => {
782
+ t.plan(24)
783
+
784
+ const fastify = Fastify({ logger: true })
785
+
786
+ fastify.decorateRequest('array_holder')
787
+ fastify.decorateRequest('my_array', {
788
+ getter () {
789
+ this.array_holder ??= []
790
+ return this.array_holder
791
+ }
792
+ })
793
+
794
+ fastify.get('/', async function (req, reply) {
795
+ t.assert.deepStrictEqual(req.my_array, [])
796
+ req.my_array.push(req.id)
797
+ t.assert.deepStrictEqual(req.my_array, [req.id])
798
+ })
799
+
800
+ fastify.addHook('onResponse', async function hook (req, reply) {
801
+ t.assert.deepStrictEqual(req.my_array, [req.id])
802
+ })
803
+
804
+ await Promise.all([
805
+ fastify.inject('/').then(res => t.assert.strictEqual(res.statusCode, 200)),
806
+ fastify.inject('/').then(res => t.assert.strictEqual(res.statusCode, 200)),
807
+ fastify.inject('/').then(res => t.assert.strictEqual(res.statusCode, 200)),
808
+ fastify.inject('/').then(res => t.assert.strictEqual(res.statusCode, 200)),
809
+ fastify.inject('/').then(res => t.assert.strictEqual(res.statusCode, 200)),
810
+ fastify.inject('/').then(res => t.assert.strictEqual(res.statusCode, 200))
811
+ ])
812
+ })
813
+
814
+ test('decorate* should not emit error if string,bool,numbers are passed', t => {
815
+ const fastify = Fastify()
816
+
817
+ fastify.decorateRequest('test_str', 'foo')
818
+ fastify.decorateRequest('test_bool', true)
819
+ fastify.decorateRequest('test_number', 42)
820
+ fastify.decorateRequest('test_null', null)
821
+ fastify.decorateRequest('test_undefined', undefined)
822
+ fastify.decorateReply('test_str', 'foo')
823
+ fastify.decorateReply('test_bool', true)
824
+ fastify.decorateReply('test_number', 42)
825
+ fastify.decorateReply('test_null', null)
826
+ fastify.decorateReply('test_undefined', undefined)
827
+ t.assert.ok('Done')
828
+ })
829
+
830
+ test('Request/reply decorators should be able to access the server instance', async t => {
831
+ t.plan(6)
832
+
833
+ const server = require('..')({ logger: false })
834
+ server.decorateRequest('assert', rootAssert)
835
+ server.decorateReply('assert', rootAssert)
836
+
837
+ server.get('/root-assert', async (req, res) => {
838
+ req.assert()
839
+ res.assert()
840
+ return 'done'
841
+ })
842
+
843
+ server.register(async instance => {
844
+ instance.decorateRequest('assert', nestedAssert)
845
+ instance.decorateReply('assert', nestedAssert)
846
+ instance.decorate('foo', 'bar')
847
+
848
+ instance.get('/nested-assert', async (req, res) => {
849
+ req.assert()
850
+ res.assert()
851
+ return 'done'
852
+ })
853
+ })
854
+
855
+ await server.inject({ method: 'GET', url: '/root-assert' })
856
+ await server.inject({ method: 'GET', url: '/nested-assert' })
857
+
858
+ // ----
859
+ function rootAssert () {
860
+ t.assert.strictEqual(this.server, server)
861
+ }
862
+
863
+ function nestedAssert () {
864
+ t.assert.notStrictEqual(this.server, server)
865
+ t.assert.strictEqual(this.server.foo, 'bar')
866
+ }
867
+ })
868
+
869
+ test('plugin required decorators', async t => {
870
+ const plugin1 = fp(
871
+ async (instance) => {
872
+ instance.decorateRequest('someThing', null)
873
+
874
+ instance.addHook('onRequest', async (request, reply) => {
875
+ request.someThing = 'hello'
876
+ })
877
+ },
878
+ {
879
+ name: 'custom-plugin-one'
880
+ }
881
+ )
882
+
883
+ const plugin2 = fp(
884
+ async () => {
885
+ // nothing
886
+ },
887
+ {
888
+ name: 'custom-plugin-two',
889
+ dependencies: ['custom-plugin-one'],
890
+ decorators: {
891
+ request: ['someThing']
892
+ }
893
+ }
894
+ )
895
+
896
+ const app = Fastify()
897
+ app.register(plugin1)
898
+ app.register(plugin2)
899
+ await app.ready()
900
+ })
901
+
902
+ test('decorateRequest/decorateReply empty string', async t => {
903
+ t.plan(6)
904
+ const fastify = Fastify()
905
+
906
+ fastify.decorateRequest('test', '')
907
+ fastify.decorateReply('test2', '')
908
+ fastify.get('/yes', (req, reply) => {
909
+ t.assert.strictEqual(req.test, '')
910
+ t.assert.strictEqual(reply.test2, '')
911
+ reply.send({ hello: 'world' })
912
+ })
913
+ t.after(() => fastify.close())
914
+
915
+ const fastifyServer = await fastify.listen({ port: 0 })
916
+ t.after(() => fastify.close())
917
+
918
+ const result = await fetch(`${fastifyServer}/yes`)
919
+ t.assert.ok(result.ok)
920
+ t.assert.strictEqual(result.status, 200)
921
+ const body = await result.text()
922
+ t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
923
+ t.assert.deepStrictEqual(JSON.parse(body), { hello: 'world' })
924
+ })
925
+
926
+ test('decorateRequest/decorateReply is undefined', async t => {
927
+ t.plan(6)
928
+ const fastify = Fastify()
929
+
930
+ fastify.decorateRequest('test', undefined)
931
+ fastify.decorateReply('test2', undefined)
932
+ fastify.get('/yes', (req, reply) => {
933
+ t.assert.strictEqual(req.test, undefined)
934
+ t.assert.strictEqual(reply.test2, undefined)
935
+ reply.send({ hello: 'world' })
936
+ })
937
+ t.after(() => fastify.close())
938
+
939
+ const fastifyServer = await fastify.listen({ port: 0 })
940
+ t.after(() => fastify.close())
941
+
942
+ const result = await fetch(`${fastifyServer}/yes`)
943
+ t.assert.ok(result.ok)
944
+ t.assert.strictEqual(result.status, 200)
945
+ const body = await result.text()
946
+ t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
947
+ t.assert.deepStrictEqual(JSON.parse(body), { hello: 'world' })
948
+ })
949
+
950
+ test('decorateRequest/decorateReply is not set to a value', async t => {
951
+ t.plan(6)
952
+ const fastify = Fastify()
953
+
954
+ fastify.decorateRequest('test')
955
+ fastify.decorateReply('test2')
956
+ fastify.get('/yes', (req, reply) => {
957
+ t.assert.strictEqual(req.test, undefined)
958
+ t.assert.strictEqual(reply.test2, undefined)
959
+ reply.send({ hello: 'world' })
960
+ })
961
+ t.after(() => fastify.close())
962
+
963
+ const fastifyServer = await fastify.listen({ port: 0 })
964
+ t.after(() => fastify.close())
965
+
966
+ const result = await fetch(`${fastifyServer}/yes`)
967
+ t.assert.ok(result.ok)
968
+ t.assert.strictEqual(result.status, 200)
969
+ const body = await result.text()
970
+ t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
971
+ t.assert.deepStrictEqual(JSON.parse(body), { hello: 'world' })
972
+ })
973
+
974
+ test('decorateRequest with dependencies', (t, done) => {
975
+ t.plan(2)
976
+ const app = Fastify()
977
+
978
+ const decorator1 = 'bar'
979
+ const decorator2 = 'foo'
980
+
981
+ app.decorate('decorator1', decorator1)
982
+ app.decorateRequest('decorator1', decorator1)
983
+
984
+ if (
985
+ app.hasDecorator('decorator1') &&
986
+ app.hasRequestDecorator('decorator1')
987
+ ) {
988
+ t.assert.doesNotThrow(() => app.decorateRequest('decorator2', decorator2, ['decorator1']))
989
+ t.assert.ok(app.hasRequestDecorator('decorator2'))
990
+ done()
991
+ }
992
+ })
993
+
994
+ test('decorateRequest with dependencies (functions)', (t, done) => {
995
+ t.plan(2)
996
+ const app = Fastify()
997
+
998
+ const decorator1 = () => 'bar'
999
+ const decorator2 = () => 'foo'
1000
+
1001
+ app.decorate('decorator1', decorator1)
1002
+ app.decorateRequest('decorator1', decorator1)
1003
+
1004
+ if (
1005
+ app.hasDecorator('decorator1') &&
1006
+ app.hasRequestDecorator('decorator1')
1007
+ ) {
1008
+ t.assert.doesNotThrow(() => app.decorateRequest('decorator2', decorator2, ['decorator1']))
1009
+ t.assert.ok(app.hasRequestDecorator('decorator2'))
1010
+ done()
1011
+ }
1012
+ })
1013
+
1014
+ test('chain of decorators on Request', async t => {
1015
+ const fastify = Fastify()
1016
+ fastify.register(fp(async function (fastify) {
1017
+ fastify.decorateRequest('foo', 'toto')
1018
+ fastify.decorateRequest('bar', () => 'tata')
1019
+ }, {
1020
+ name: 'first'
1021
+ }))
1022
+
1023
+ fastify.get('/foo', async function (request, reply) {
1024
+ return request.foo
1025
+ })
1026
+ fastify.get('/bar', function (request, reply) {
1027
+ return request.bar()
1028
+ })
1029
+ fastify.register(async function second (fastify) {
1030
+ fastify.get('/foo', async function (request, reply) {
1031
+ return request.foo
1032
+ })
1033
+ fastify.get('/bar', async function (request, reply) {
1034
+ return request.bar()
1035
+ })
1036
+ fastify.register(async function fourth (fastify) {
1037
+ fastify.get('/plugin3/foo', async function (request, reply) {
1038
+ return request.foo
1039
+ })
1040
+ fastify.get('/plugin3/bar', function (request, reply) {
1041
+ return request.bar()
1042
+ })
1043
+ })
1044
+ fastify.register(fp(async function (fastify) {
1045
+ fastify.decorateRequest('fooB', 'toto')
1046
+ fastify.decorateRequest('barB', () => 'tata')
1047
+ }, {
1048
+ name: 'third'
1049
+ }))
1050
+ },
1051
+ { prefix: '/plugin2', name: 'plugin2' }
1052
+ )
1053
+
1054
+ await fastify.ready()
1055
+
1056
+ {
1057
+ const response = await fastify.inject('/foo')
1058
+ t.assert.strictEqual(response.body, 'toto')
1059
+ }
1060
+
1061
+ {
1062
+ const response = await fastify.inject('/bar')
1063
+ t.assert.strictEqual(response.body, 'tata')
1064
+ }
1065
+
1066
+ {
1067
+ const response = await fastify.inject('/plugin2/foo')
1068
+ t.assert.strictEqual(response.body, 'toto')
1069
+ }
1070
+
1071
+ {
1072
+ const response = await fastify.inject('/plugin2/bar')
1073
+ t.assert.strictEqual(response.body, 'tata')
1074
+ }
1075
+
1076
+ {
1077
+ const response = await fastify.inject('/plugin2/plugin3/foo')
1078
+ t.assert.strictEqual(response.body, 'toto')
1079
+ }
1080
+
1081
+ {
1082
+ const response = await fastify.inject('/plugin2/plugin3/bar')
1083
+ t.assert.strictEqual(response.body, 'tata')
1084
+ }
1085
+ })
1086
+
1087
+ test('chain of decorators on Reply', async (t) => {
1088
+ const fastify = Fastify()
1089
+ fastify.register(fp(async function (fastify) {
1090
+ fastify.decorateReply('foo', 'toto')
1091
+ fastify.decorateReply('bar', () => 'tata')
1092
+ }, {
1093
+ name: 'first'
1094
+ }))
1095
+
1096
+ fastify.get('/foo', async function (request, reply) {
1097
+ return reply.foo
1098
+ })
1099
+ fastify.get('/bar', function (request, reply) {
1100
+ return reply.bar()
1101
+ })
1102
+ fastify.register(async function second (fastify) {
1103
+ fastify.get('/foo', async function (request, reply) {
1104
+ return reply.foo
1105
+ })
1106
+ fastify.get('/bar', async function (request, reply) {
1107
+ return reply.bar()
1108
+ })
1109
+ fastify.register(async function fourth (fastify) {
1110
+ fastify.get('/plugin3/foo', async function (request, reply) {
1111
+ return reply.foo
1112
+ })
1113
+ fastify.get('/plugin3/bar', function (request, reply) {
1114
+ return reply.bar()
1115
+ })
1116
+ })
1117
+ fastify.register(fp(async function (fastify) {
1118
+ fastify.decorateReply('fooB', 'toto')
1119
+ fastify.decorateReply('barB', () => 'tata')
1120
+ }, {
1121
+ name: 'third'
1122
+ }))
1123
+ },
1124
+ { prefix: '/plugin2', name: 'plugin2' }
1125
+ )
1126
+
1127
+ await fastify.ready()
1128
+
1129
+ {
1130
+ const response = await fastify.inject('/foo')
1131
+ t.assert.strictEqual(response.body, 'toto')
1132
+ }
1133
+
1134
+ {
1135
+ const response = await fastify.inject('/bar')
1136
+ t.assert.strictEqual(response.body, 'tata')
1137
+ }
1138
+
1139
+ {
1140
+ const response = await fastify.inject('/plugin2/foo')
1141
+ t.assert.strictEqual(response.body, 'toto')
1142
+ }
1143
+
1144
+ {
1145
+ const response = await fastify.inject('/plugin2/bar')
1146
+ t.assert.strictEqual(response.body, 'tata')
1147
+ }
1148
+
1149
+ {
1150
+ const response = await fastify.inject('/plugin2/plugin3/foo')
1151
+ t.assert.strictEqual(response.body, 'toto')
1152
+ }
1153
+
1154
+ {
1155
+ const response = await fastify.inject('/plugin2/plugin3/bar')
1156
+ t.assert.strictEqual(response.body, 'tata')
1157
+ }
1158
+ })
1159
+
1160
+ test('getDecorator should return the decorator', (t, done) => {
1161
+ t.plan(12)
1162
+ const fastify = Fastify()
1163
+
1164
+ fastify.decorate('root', 'from_root')
1165
+ fastify.decorateRequest('root', 'from_root_request')
1166
+ fastify.decorateReply('root', 'from_root_reply')
1167
+
1168
+ t.assert.strictEqual(fastify.getDecorator('root'), 'from_root')
1169
+ fastify.get('/', async (req, res) => {
1170
+ t.assert.strictEqual(req.getDecorator('root'), 'from_root_request')
1171
+ t.assert.strictEqual(res.getDecorator('root'), 'from_root_reply')
1172
+
1173
+ res.send()
1174
+ })
1175
+
1176
+ fastify.register((child) => {
1177
+ child.decorate('child', 'from_child')
1178
+
1179
+ t.assert.strictEqual(child.getDecorator('child'), 'from_child')
1180
+ t.assert.strictEqual(child.getDecorator('root'), 'from_root')
1181
+
1182
+ child.get('/child', async (req, res) => {
1183
+ t.assert.strictEqual(req.getDecorator('root'), 'from_root_request')
1184
+ t.assert.strictEqual(res.getDecorator('root'), 'from_root_reply')
1185
+
1186
+ res.send()
1187
+ })
1188
+ })
1189
+
1190
+ fastify.ready((err) => {
1191
+ t.assert.ifError(err)
1192
+ fastify.inject({ url: '/' }, (err, res) => {
1193
+ t.assert.ifError(err)
1194
+ t.assert.ok(true)
1195
+ })
1196
+
1197
+ fastify.inject({ url: '/child' }, (err, res) => {
1198
+ t.assert.ifError(err)
1199
+ t.assert.ok(true)
1200
+ done()
1201
+ })
1202
+ })
1203
+ })
1204
+
1205
+ test('getDecorator should return function decorators with expected binded context', (t, done) => {
1206
+ t.plan(12)
1207
+ const fastify = Fastify()
1208
+
1209
+ fastify.decorate('a', function () {
1210
+ return this
1211
+ })
1212
+ fastify.decorateRequest('b', function () {
1213
+ return this
1214
+ })
1215
+ fastify.decorateReply('c', function () {
1216
+ return this
1217
+ })
1218
+
1219
+ fastify.register((child) => {
1220
+ child.decorate('a', function () {
1221
+ return this
1222
+ })
1223
+
1224
+ t.assert.deepEqual(child.getDecorator('a')(), child)
1225
+ child.get('/child', async (req, res) => {
1226
+ t.assert.deepEqual(req.getDecorator('b')(), req)
1227
+ t.assert.deepEqual(res.getDecorator('c')(), res)
1228
+
1229
+ res.send()
1230
+ })
1231
+ })
1232
+
1233
+ t.assert.deepEqual(fastify.getDecorator('a')(), fastify)
1234
+ fastify.get('/', async (req, res) => {
1235
+ t.assert.deepEqual(req.getDecorator('b')(), req)
1236
+ t.assert.deepEqual(res.getDecorator('c')(), res)
1237
+ res.send()
1238
+ })
1239
+
1240
+ fastify.ready((err) => {
1241
+ t.assert.ifError(err)
1242
+ fastify.inject({ url: '/' }, (err, res) => {
1243
+ t.assert.ifError(err)
1244
+ t.assert.ok(true, 'passed')
1245
+ })
1246
+
1247
+ fastify.inject({ url: '/child' }, (err, res) => {
1248
+ t.assert.ifError(err)
1249
+ t.assert.ok(true, 'passed')
1250
+ done()
1251
+ })
1252
+ t.assert.ok(true, 'passed')
1253
+ })
1254
+ })
1255
+
1256
+ test('getDecorator should only return decorators existing in the scope', (t, done) => {
1257
+ t.plan(9)
1258
+
1259
+ function assertsThrowOnUndeclaredDecorator (notDecorated, instanceType) {
1260
+ try {
1261
+ notDecorated.getDecorator('foo')
1262
+ t.assert.fail()
1263
+ } catch (e) {
1264
+ t.assert.deepEqual(e.code, 'FST_ERR_DEC_UNDECLARED')
1265
+ t.assert.deepEqual(e.message, `No decorator 'foo' has been declared on ${instanceType}.`)
1266
+ }
1267
+ }
1268
+
1269
+ const fastify = Fastify()
1270
+ fastify.register(child => {
1271
+ child.decorate('foo', true)
1272
+ child.decorateRequest('foo', true)
1273
+ child.decorateReply('foo', true)
1274
+ })
1275
+
1276
+ fastify.get('/', async (req, res) => {
1277
+ assertsThrowOnUndeclaredDecorator(req, 'request')
1278
+ assertsThrowOnUndeclaredDecorator(res, 'reply')
1279
+
1280
+ return { hello: 'world' }
1281
+ })
1282
+
1283
+ fastify.ready((err) => {
1284
+ t.assert.ifError(err)
1285
+
1286
+ assertsThrowOnUndeclaredDecorator(fastify, 'instance')
1287
+ fastify.inject({ url: '/' }, (err, res) => {
1288
+ t.assert.ifError(err)
1289
+ t.assert.ok(true, 'passed')
1290
+ done()
1291
+ })
1292
+ })
1293
+ })
1294
+
1295
+ test('Request.setDecorator should update an existing decorator', (t, done) => {
1296
+ t.plan(7)
1297
+ const fastify = Fastify()
1298
+
1299
+ fastify.decorateRequest('session', null)
1300
+ fastify.decorateRequest('utility', null)
1301
+ fastify.addHook('onRequest', async (req, reply) => {
1302
+ req.setDecorator('session', { user: 'Jean' })
1303
+ req.setDecorator('utility', function () {
1304
+ return this
1305
+ })
1306
+ try {
1307
+ req.setDecorator('foo', { user: 'Jean' })
1308
+ t.assert.fail()
1309
+ } catch (e) {
1310
+ t.assert.deepEqual(e.code, 'FST_ERR_DEC_UNDECLARED')
1311
+ t.assert.deepEqual(e.message, "No decorator 'foo' has been declared on request.")
1312
+ }
1313
+ })
1314
+
1315
+ fastify.get('/', async (req, res) => {
1316
+ t.assert.deepEqual(req.getDecorator('session'), { user: 'Jean' })
1317
+ t.assert.deepEqual(req.getDecorator('utility')(), req)
1318
+
1319
+ res.send()
1320
+ })
1321
+
1322
+ fastify.ready((err) => {
1323
+ t.assert.ifError(err)
1324
+ fastify.inject({ url: '/' }, (err, res) => {
1325
+ t.assert.ifError(err)
1326
+ t.assert.ok(true, 'passed')
1327
+ done()
1328
+ })
1329
+ })
1330
+ })