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,164 @@
1
+ 'use strict'
2
+
3
+ const { buildSchemas } = require('./schemas')
4
+
5
+ /**
6
+ * Called at every fastify context that is being created.
7
+ * @param {object} parentSchemaCtrl: the SchemaController instance of the Fastify parent context
8
+ * @param {object} opts: the `schemaController` server option. It can be undefined when a parentSchemaCtrl is set
9
+ * @return {object}:a new SchemaController
10
+ */
11
+ function buildSchemaController (parentSchemaCtrl, opts) {
12
+ if (parentSchemaCtrl) {
13
+ return new SchemaController(parentSchemaCtrl, opts)
14
+ }
15
+
16
+ const compilersFactory = Object.assign({
17
+ buildValidator: null,
18
+ buildSerializer: null
19
+ }, opts?.compilersFactory)
20
+
21
+ if (!compilersFactory.buildValidator) {
22
+ const ValidatorSelector = require('@fastify/ajv-compiler')
23
+ compilersFactory.buildValidator = ValidatorSelector()
24
+ }
25
+ if (!compilersFactory.buildSerializer) {
26
+ const SerializerSelector = require('@fastify/fast-json-stringify-compiler')
27
+ compilersFactory.buildSerializer = SerializerSelector()
28
+ }
29
+
30
+ const option = {
31
+ bucket: (opts && opts.bucket) || buildSchemas,
32
+ compilersFactory,
33
+ isCustomValidatorCompiler: typeof opts?.compilersFactory?.buildValidator === 'function',
34
+ isCustomSerializerCompiler: typeof opts?.compilersFactory?.buildValidator === 'function'
35
+ }
36
+
37
+ return new SchemaController(undefined, option)
38
+ }
39
+
40
+ class SchemaController {
41
+ constructor (parent, options) {
42
+ this.opts = options || parent?.opts
43
+ this.addedSchemas = false
44
+
45
+ this.compilersFactory = this.opts.compilersFactory
46
+
47
+ if (parent) {
48
+ this.schemaBucket = this.opts.bucket(parent.getSchemas())
49
+ this.validatorCompiler = parent.getValidatorCompiler()
50
+ this.serializerCompiler = parent.getSerializerCompiler()
51
+ this.isCustomValidatorCompiler = parent.isCustomValidatorCompiler
52
+ this.isCustomSerializerCompiler = parent.isCustomSerializerCompiler
53
+ this.parent = parent
54
+ } else {
55
+ this.schemaBucket = this.opts.bucket()
56
+ this.isCustomValidatorCompiler = this.opts.isCustomValidatorCompiler || false
57
+ this.isCustomSerializerCompiler = this.opts.isCustomSerializerCompiler || false
58
+ }
59
+ }
60
+
61
+ // Bucket interface
62
+ add (schema) {
63
+ this.addedSchemas = true
64
+ return this.schemaBucket.add(schema)
65
+ }
66
+
67
+ getSchema (schemaId) {
68
+ return this.schemaBucket.getSchema(schemaId)
69
+ }
70
+
71
+ getSchemas () {
72
+ return this.schemaBucket.getSchemas()
73
+ }
74
+
75
+ setValidatorCompiler (validatorCompiler) {
76
+ // Set up as if the fixed validator compiler had been provided
77
+ // by a custom 'options.compilersFactory.buildValidator' that
78
+ // always returns the same compiler object. This is required because:
79
+ //
80
+ // - setValidatorCompiler must immediately install a compiler to preserve
81
+ // legacy behavior
82
+ // - setupValidator will recreate compilers from builders in some
83
+ // circumstances, so we have to install this adapter to make it
84
+ // behave the same if the legacy API is used
85
+ //
86
+ // The cloning of the compilersFactory object is necessary because
87
+ // we are aliasing the parent compilersFactory if none was provided
88
+ // to us (see constructor.)
89
+ this.compilersFactory = Object.assign(
90
+ {},
91
+ this.compilersFactory,
92
+ { buildValidator: () => validatorCompiler })
93
+ this.validatorCompiler = validatorCompiler
94
+ this.isCustomValidatorCompiler = true
95
+ }
96
+
97
+ setSerializerCompiler (serializerCompiler) {
98
+ // Set up as if the fixed serializer compiler had been provided
99
+ // by a custom 'options.compilersFactory.buildSerializer' that
100
+ // always returns the same compiler object. This is required because:
101
+ //
102
+ // - setSerializerCompiler must immediately install a compiler to preserve
103
+ // legacy behavior
104
+ // - setupSerializer will recreate compilers from builders in some
105
+ // circumstances, so we have to install this adapter to make it
106
+ // behave the same if the legacy API is used
107
+ //
108
+ // The cloning of the compilersFactory object is necessary because
109
+ // we are aliasing the parent compilersFactory if none was provided
110
+ // to us (see constructor.)
111
+ this.compilersFactory = Object.assign(
112
+ {},
113
+ this.compilersFactory,
114
+ { buildSerializer: () => serializerCompiler })
115
+ this.serializerCompiler = serializerCompiler
116
+ this.isCustomSerializerCompiler = true
117
+ }
118
+
119
+ getValidatorCompiler () {
120
+ return this.validatorCompiler || (this.parent && this.parent.getValidatorCompiler())
121
+ }
122
+
123
+ getSerializerCompiler () {
124
+ return this.serializerCompiler || (this.parent && this.parent.getSerializerCompiler())
125
+ }
126
+
127
+ getSerializerBuilder () {
128
+ return this.compilersFactory.buildSerializer || (this.parent && this.parent.getSerializerBuilder())
129
+ }
130
+
131
+ getValidatorBuilder () {
132
+ return this.compilersFactory.buildValidator || (this.parent && this.parent.getValidatorBuilder())
133
+ }
134
+
135
+ /**
136
+ * This method will be called when a validator must be setup.
137
+ * Do not setup the compiler more than once
138
+ * @param {object} serverOptions the fastify server options
139
+ */
140
+ setupValidator (serverOptions) {
141
+ const isReady = this.validatorCompiler !== undefined && !this.addedSchemas
142
+ if (isReady) {
143
+ return
144
+ }
145
+ this.validatorCompiler = this.getValidatorBuilder()(this.schemaBucket.getSchemas(), serverOptions.ajv)
146
+ }
147
+
148
+ /**
149
+ * This method will be called when a serializer must be setup.
150
+ * Do not setup the compiler more than once
151
+ * @param {object} serverOptions the fastify server options
152
+ */
153
+ setupSerializer (serverOptions) {
154
+ const isReady = this.serializerCompiler !== undefined && !this.addedSchemas
155
+ if (isReady) {
156
+ return
157
+ }
158
+
159
+ this.serializerCompiler = this.getSerializerBuilder()(this.schemaBucket.getSchemas(), serverOptions.serializerOpts)
160
+ }
161
+ }
162
+
163
+ SchemaController.buildSchemaController = buildSchemaController
164
+ module.exports = SchemaController
package/lib/schemas.js ADDED
@@ -0,0 +1,207 @@
1
+ 'use strict'
2
+
3
+ const fastClone = require('rfdc')({ circles: false, proto: true })
4
+ const { kSchemaVisited, kSchemaResponse } = require('./symbols')
5
+ const kFluentSchema = Symbol.for('fluent-schema-object')
6
+
7
+ const {
8
+ FST_ERR_SCH_MISSING_ID,
9
+ FST_ERR_SCH_ALREADY_PRESENT,
10
+ FST_ERR_SCH_DUPLICATE,
11
+ FST_ERR_SCH_CONTENT_MISSING_SCHEMA
12
+ } = require('./errors')
13
+
14
+ const SCHEMAS_SOURCE = ['params', 'body', 'querystring', 'query', 'headers']
15
+
16
+ function Schemas (initStore) {
17
+ this.store = initStore || {}
18
+ }
19
+
20
+ Schemas.prototype.add = function (inputSchema) {
21
+ const schema = fastClone((inputSchema.isFluentSchema || inputSchema.isFluentJSONSchema || inputSchema[kFluentSchema])
22
+ ? inputSchema.valueOf()
23
+ : inputSchema
24
+ )
25
+
26
+ // developers can add schemas without $id, but with $def instead
27
+ const id = schema.$id
28
+ if (!id) {
29
+ throw new FST_ERR_SCH_MISSING_ID()
30
+ }
31
+
32
+ if (this.store[id]) {
33
+ throw new FST_ERR_SCH_ALREADY_PRESENT(id)
34
+ }
35
+
36
+ this.store[id] = schema
37
+ }
38
+
39
+ Schemas.prototype.getSchemas = function () {
40
+ return Object.assign({}, this.store)
41
+ }
42
+
43
+ Schemas.prototype.getSchema = function (schemaId) {
44
+ return this.store[schemaId]
45
+ }
46
+
47
+ /**
48
+ * Checks whether a schema is a non-plain object.
49
+ *
50
+ * @param {*} schema the schema to check
51
+ * @returns {boolean} true if schema has a custom prototype
52
+ */
53
+ function isCustomSchemaPrototype (schema) {
54
+ return typeof schema === 'object' && Object.getPrototypeOf(schema) !== Object.prototype
55
+ }
56
+
57
+ function normalizeSchema (routeSchemas, serverOptions) {
58
+ if (routeSchemas[kSchemaVisited]) {
59
+ return routeSchemas
60
+ }
61
+
62
+ // alias query to querystring schema
63
+ if (routeSchemas.query) {
64
+ // check if our schema has both querystring and query
65
+ if (routeSchemas.querystring) {
66
+ throw new FST_ERR_SCH_DUPLICATE('querystring')
67
+ }
68
+ routeSchemas.querystring = routeSchemas.query
69
+ }
70
+
71
+ generateFluentSchema(routeSchemas)
72
+
73
+ for (const key of SCHEMAS_SOURCE) {
74
+ const schema = routeSchemas[key]
75
+ if (schema && !isCustomSchemaPrototype(schema)) {
76
+ if (key === 'body' && schema.content) {
77
+ const contentProperty = schema.content
78
+ const keys = Object.keys(contentProperty)
79
+ for (let i = 0; i < keys.length; i++) {
80
+ const contentType = keys[i]
81
+ const contentSchema = contentProperty[contentType].schema
82
+ if (!contentSchema) {
83
+ throw new FST_ERR_SCH_CONTENT_MISSING_SCHEMA(contentType)
84
+ }
85
+ }
86
+ continue
87
+ }
88
+ }
89
+ }
90
+
91
+ if (routeSchemas.response) {
92
+ const httpCodes = Object.keys(routeSchemas.response)
93
+ for (const code of httpCodes) {
94
+ if (isCustomSchemaPrototype(routeSchemas.response[code])) {
95
+ continue
96
+ }
97
+
98
+ const contentProperty = routeSchemas.response[code].content
99
+
100
+ if (contentProperty) {
101
+ const keys = Object.keys(contentProperty)
102
+ for (let i = 0; i < keys.length; i++) {
103
+ const mediaName = keys[i]
104
+ if (!contentProperty[mediaName].schema) {
105
+ throw new FST_ERR_SCH_CONTENT_MISSING_SCHEMA(mediaName)
106
+ }
107
+ }
108
+ }
109
+ }
110
+ }
111
+
112
+ routeSchemas[kSchemaVisited] = true
113
+ return routeSchemas
114
+ }
115
+
116
+ function generateFluentSchema (schema) {
117
+ for (const key of SCHEMAS_SOURCE) {
118
+ if (schema[key] && (schema[key].isFluentSchema || schema[key][kFluentSchema])) {
119
+ schema[key] = schema[key].valueOf()
120
+ }
121
+ }
122
+
123
+ if (schema.response) {
124
+ const httpCodes = Object.keys(schema.response)
125
+ for (const code of httpCodes) {
126
+ if (schema.response[code].isFluentSchema || schema.response[code][kFluentSchema]) {
127
+ schema.response[code] = schema.response[code].valueOf()
128
+ }
129
+ }
130
+ }
131
+ }
132
+
133
+ /**
134
+ * Search for the right JSON schema compiled function in the request context
135
+ * setup by the route configuration `schema.response`.
136
+ * It will look for the exact match (eg 200) or generic (eg 2xx)
137
+ *
138
+ * @param {object} context the request context
139
+ * @param {number} statusCode the http status code
140
+ * @param {string} [contentType] the reply content type
141
+ * @returns {function|false} the right JSON Schema function to serialize
142
+ * the reply or false if it is not set
143
+ */
144
+ function getSchemaSerializer (context, statusCode, contentType) {
145
+ const responseSchemaDef = context[kSchemaResponse]
146
+ if (!responseSchemaDef) {
147
+ return false
148
+ }
149
+ if (responseSchemaDef[statusCode]) {
150
+ if (responseSchemaDef[statusCode].constructor === Object && contentType) {
151
+ const mediaName = contentType.split(';', 1)[0]
152
+ if (responseSchemaDef[statusCode][mediaName]) {
153
+ return responseSchemaDef[statusCode][mediaName]
154
+ }
155
+
156
+ // fallback to match all media-type
157
+ if (responseSchemaDef[statusCode]['*/*']) {
158
+ return responseSchemaDef[statusCode]['*/*']
159
+ }
160
+
161
+ return false
162
+ }
163
+ return responseSchemaDef[statusCode]
164
+ }
165
+ const fallbackStatusCode = (statusCode + '')[0] + 'xx'
166
+ if (responseSchemaDef[fallbackStatusCode]) {
167
+ if (responseSchemaDef[fallbackStatusCode].constructor === Object && contentType) {
168
+ const mediaName = contentType.split(';', 1)[0]
169
+ if (responseSchemaDef[fallbackStatusCode][mediaName]) {
170
+ return responseSchemaDef[fallbackStatusCode][mediaName]
171
+ }
172
+
173
+ // fallback to match all media-type
174
+ if (responseSchemaDef[fallbackStatusCode]['*/*']) {
175
+ return responseSchemaDef[fallbackStatusCode]['*/*']
176
+ }
177
+
178
+ return false
179
+ }
180
+
181
+ return responseSchemaDef[fallbackStatusCode]
182
+ }
183
+ if (responseSchemaDef.default) {
184
+ if (responseSchemaDef.default.constructor === Object && contentType) {
185
+ const mediaName = contentType.split(';', 1)[0]
186
+ if (responseSchemaDef.default[mediaName]) {
187
+ return responseSchemaDef.default[mediaName]
188
+ }
189
+
190
+ // fallback to match all media-type
191
+ if (responseSchemaDef.default['*/*']) {
192
+ return responseSchemaDef.default['*/*']
193
+ }
194
+
195
+ return false
196
+ }
197
+
198
+ return responseSchemaDef.default
199
+ }
200
+ return false
201
+ }
202
+
203
+ module.exports = {
204
+ buildSchemas (initStore) { return new Schemas(initStore) },
205
+ getSchemaSerializer,
206
+ normalizeSchema
207
+ }