fastify 4.0.2 → 4.2.0

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 (48) hide show
  1. package/.eslintrc +1 -0
  2. package/README.md +3 -3
  3. package/docs/Guides/Database.md +5 -5
  4. package/docs/Guides/Delay-Accepting-Requests.md +1 -1
  5. package/docs/Guides/Ecosystem.md +13 -0
  6. package/docs/Guides/Migration-Guide-V4.md +58 -2
  7. package/docs/Guides/Serverless.md +23 -10
  8. package/docs/Reference/Hooks.md +52 -0
  9. package/docs/Reference/LTS.md +2 -2
  10. package/docs/Reference/Plugins.md +1 -1
  11. package/docs/Reference/Server.md +1 -1
  12. package/docs/Reference/Type-Providers.md +4 -3
  13. package/docs/Reference/TypeScript.md +38 -25
  14. package/docs/Reference/Validation-and-Serialization.md +11 -0
  15. package/docs/index.md +1 -1
  16. package/fastify.d.ts +3 -3
  17. package/fastify.js +19 -19
  18. package/integration/server.js +27 -0
  19. package/integration/test.sh +23 -0
  20. package/lib/context.js +5 -2
  21. package/lib/error-serializer.js +173 -8
  22. package/lib/handleRequest.js +1 -1
  23. package/lib/reply.js +2 -0
  24. package/lib/route.js +39 -29
  25. package/lib/server.js +9 -1
  26. package/lib/symbols.js +2 -1
  27. package/lib/validation.js +2 -0
  28. package/lib/wrapThenable.js +8 -3
  29. package/package.json +6 -6
  30. package/test/404s.test.js +2 -2
  31. package/test/build/error-serializer.test.js +6 -1
  32. package/test/hooks.test.js +21 -0
  33. package/test/internals/reply.test.js +12 -0
  34. package/test/listen.test.js +16 -2
  35. package/test/pretty-print.test.js +3 -3
  36. package/test/reply-error.test.js +1 -1
  37. package/test/schema-feature.test.js +2 -2
  38. package/test/stream.test.js +73 -0
  39. package/test/types/fastify.test-d.ts +12 -1
  40. package/test/types/instance.test-d.ts +1 -1
  41. package/test/types/register.test-d.ts +77 -2
  42. package/test/types/request.test-d.ts +8 -4
  43. package/test/types/type-provider.test-d.ts +11 -2
  44. package/test/validation-error-handling.test.js +32 -0
  45. package/types/register.d.ts +9 -7
  46. package/types/route.d.ts +10 -12
  47. package/types/schema.d.ts +1 -1
  48. package/types/type-provider.d.ts +12 -5
@@ -324,7 +324,7 @@ test('invalid schema - ajv', t => {
324
324
 
325
325
  fastify.setErrorHandler((err, request, reply) => {
326
326
  t.ok(Array.isArray(err.validation))
327
- reply.send('error')
327
+ reply.code(400).send('error')
328
328
  })
329
329
 
330
330
  fastify.inject({
@@ -206,7 +206,7 @@ test('Should throw of the schema does not exists in output', t => {
206
206
 
207
207
  fastify.ready(err => {
208
208
  t.equal(err.code, 'FST_ERR_SCH_SERIALIZATION_BUILD')
209
- t.match(err.message, /^Failed building the serialization schema for GET: \/:id, due to error Cannot read propert.*/) // error from fast-json-strinfigy
209
+ t.match(err.message, /^Failed building the serialization schema for GET: \/:id, due to error Cannot find reference.*/) // error from fast-json-strinfigy
210
210
  })
211
211
  })
212
212
 
@@ -826,7 +826,7 @@ test('Validation context in validation result', t => {
826
826
  t.equal(err instanceof Error, true)
827
827
  t.ok(err.validation, 'detailed errors')
828
828
  t.equal(err.validationContext, 'body')
829
- reply.send()
829
+ reply.code(400).send()
830
830
  })
831
831
  fastify.post('/', {
832
832
  handler: echoParams,
@@ -741,3 +741,76 @@ test('reply.send handles aborted requests', t => {
741
741
  }, 1)
742
742
  })
743
743
  })
744
+
745
+ test('request terminated should not crash fastify', t => {
746
+ t.plan(10)
747
+
748
+ const spyLogger = {
749
+ level: 'error',
750
+ fatal: () => { },
751
+ error: () => {
752
+ t.fail('should not log an error')
753
+ },
754
+ warn: () => { },
755
+ info: () => { },
756
+ debug: () => { },
757
+ trace: () => { },
758
+ child: () => { return spyLogger }
759
+ }
760
+ const fastify = Fastify({
761
+ logger: spyLogger
762
+ })
763
+
764
+ fastify.get('/', async (req, reply) => {
765
+ const stream = new Readable()
766
+ stream._read = () => {}
767
+ reply.header('content-type', 'text/html; charset=utf-8')
768
+ reply.header('transfer-encoding', 'chunked')
769
+ stream.push('<h1>HTML</h1>')
770
+
771
+ reply.send(stream)
772
+
773
+ await new Promise((resolve) => { setTimeout(resolve, 100).unref() })
774
+
775
+ stream.push('<h1>should disply on second stream</h1>')
776
+ stream.push(null)
777
+ return reply
778
+ })
779
+
780
+ fastify.listen({ port: 0 }, err => {
781
+ t.error(err)
782
+ t.teardown(() => { fastify.close() })
783
+
784
+ const port = fastify.server.address().port
785
+ const http = require('http')
786
+ const req = http.get(`http://localhost:${port}`, function (res) {
787
+ const { statusCode, headers } = res
788
+ t.equal(statusCode, 200)
789
+ t.equal(headers['content-type'], 'text/html; charset=utf-8')
790
+ t.equal(headers['transfer-encoding'], 'chunked')
791
+ res.on('data', function (chunk) {
792
+ t.equal(chunk.toString(), '<h1>HTML</h1>')
793
+ })
794
+
795
+ setTimeout(() => {
796
+ req.destroy()
797
+
798
+ // the server is not crash, we can connect it
799
+ http.get(`http://localhost:${port}`, function (res) {
800
+ const { statusCode, headers } = res
801
+ t.equal(statusCode, 200)
802
+ t.equal(headers['content-type'], 'text/html; charset=utf-8')
803
+ t.equal(headers['transfer-encoding'], 'chunked')
804
+ let payload = ''
805
+ res.on('data', function (chunk) {
806
+ payload += chunk.toString()
807
+ })
808
+ res.on('end', function () {
809
+ t.equal(payload, '<h1>HTML</h1><h1>should disply on second stream</h1>')
810
+ t.pass('should end properly')
811
+ })
812
+ })
813
+ }, 1)
814
+ })
815
+ })
816
+ })
@@ -7,8 +7,10 @@ import fastify, {
7
7
  LightMyRequestChain,
8
8
  LightMyRequestResponse,
9
9
  LightMyRequestCallback,
10
- InjectOptions, FastifyBaseLogger
10
+ InjectOptions, FastifyBaseLogger,
11
+ ValidationResult
11
12
  } from '../../fastify'
13
+ import { ErrorObject as AjvErrorObject } from 'ajv'
12
14
  import * as http from 'http'
13
15
  import * as https from 'https'
14
16
  import * as http2 from 'http2'
@@ -208,3 +210,12 @@ fastify().then(fastifyInstance => expectAssignable<FastifyInstance>(fastifyInsta
208
210
  expectAssignable<FastifyPluginAsync>(async () => {})
209
211
  expectAssignable<FastifyPluginCallback>(() => {})
210
212
  expectAssignable<FastifyPlugin>(() => {})
213
+
214
+ const ajvErrorObject: AjvErrorObject = {
215
+ keyword: '',
216
+ instancePath: '',
217
+ schemaPath: '',
218
+ params: {},
219
+ message: ''
220
+ }
221
+ expectAssignable<ValidationResult>(ajvErrorObject)
@@ -133,7 +133,7 @@ expectError(server.setErrorHandler(invalidErrorHandler))
133
133
  server.setSchemaController({
134
134
  bucket: (parentSchemas: unknown) => {
135
135
  return {
136
- addSchema (schema: unknown) {
136
+ add (schema: unknown) {
137
137
  expectType<unknown>(schema)
138
138
  expectType<FastifyInstance>(server.addSchema({ type: 'null' }))
139
139
  return server.addSchema({ type: 'null' })
@@ -1,7 +1,21 @@
1
1
  import { expectAssignable, expectError, expectType } from 'tsd'
2
- import fastify, { FastifyInstance, FastifyPluginAsync } from '../../fastify'
2
+ import { IncomingMessage, Server, ServerResponse } from 'http'
3
+ import { Http2Server, Http2ServerRequest, Http2ServerResponse } from 'http2'
4
+ import fastify, { FastifyInstance, FastifyError, FastifyLoggerInstance, FastifyPluginAsync, FastifyPluginCallback, FastifyPluginOptions, RawServerDefault } from '../../fastify'
3
5
 
4
- const testPluginOptsAsync: FastifyPluginAsync = async function (_instance, _opts) { }
6
+ const testPluginCallback: FastifyPluginCallback = function (instance, opts, done) { }
7
+ const testPluginAsync: FastifyPluginAsync = async function (instance, opts) { }
8
+
9
+ const testPluginOpts: FastifyPluginCallback = function (instance, opts, done) { }
10
+ const testPluginOptsAsync: FastifyPluginAsync = async function (instance, opts) { }
11
+
12
+ const testPluginOptsWithType = (instance: FastifyInstance, opts: FastifyPluginOptions, done: (error?: FastifyError) => void) => { }
13
+ const testPluginOptsWithTypeAsync = async (instance: FastifyInstance, opts: FastifyPluginOptions) => { }
14
+
15
+ interface TestOptions extends FastifyPluginOptions {
16
+ option1: string;
17
+ option2: boolean;
18
+ }
5
19
 
6
20
  // Type validation
7
21
  expectError(fastify().register(testPluginOptsAsync, { prefix: 1 }))
@@ -26,3 +40,64 @@ expectAssignable<FastifyInstance>(
26
40
  expectType<FastifyInstance>(instance)
27
41
  })
28
42
  )
43
+
44
+ // With Http2
45
+ const serverWithHttp2 = fastify({ http2: true })
46
+ type ServerWithHttp2 = FastifyInstance<Http2Server, Http2ServerRequest, Http2ServerResponse>
47
+ const testPluginWithHttp2: FastifyPluginCallback<TestOptions, Http2Server> = function (instance, opts, done) { }
48
+ const testPluginWithHttp2Async: FastifyPluginAsync<TestOptions, Http2Server> = async function (instance, opts) { }
49
+ const testPluginWithHttp2WithType = (instance: ServerWithHttp2, opts: FastifyPluginOptions, done: (error?: FastifyError) => void) => { }
50
+ const testPluginWithHttp2WithTypeAsync = async (instance: ServerWithHttp2, opts: FastifyPluginOptions) => { }
51
+ expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginCallback))
52
+ expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginAsync))
53
+ expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginOpts))
54
+ expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginOptsAsync))
55
+ expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginOptsWithType))
56
+ expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginOptsWithTypeAsync))
57
+ expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginWithHttp2))
58
+ expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginWithHttp2Async))
59
+ expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginWithHttp2WithType))
60
+ expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginWithHttp2WithTypeAsync))
61
+ expectAssignable<ServerWithHttp2>(serverWithHttp2.register((instance) => {
62
+ expectAssignable<FastifyInstance>(instance)
63
+ }))
64
+ expectAssignable<ServerWithHttp2>(serverWithHttp2.register((instance: ServerWithHttp2) => {
65
+ expectAssignable<ServerWithHttp2>(instance)
66
+ }))
67
+ expectAssignable<ServerWithHttp2>(serverWithHttp2.register(async (instance) => {
68
+ expectAssignable<FastifyInstance>(instance)
69
+ }))
70
+ expectAssignable<ServerWithHttp2>(serverWithHttp2.register(async (instance: ServerWithHttp2) => {
71
+ expectAssignable<ServerWithHttp2>(instance)
72
+ }))
73
+
74
+ // With Type Provider
75
+ type TestTypeProvider = { input: 'test', output: 'test' }
76
+ const serverWithTypeProvider = fastify().withTypeProvider<TestTypeProvider>()
77
+ type ServerWithTypeProvider = FastifyInstance<Server, IncomingMessage, ServerResponse, FastifyLoggerInstance, TestTypeProvider>
78
+ const testPluginWithTypeProvider: FastifyPluginCallback<TestOptions, RawServerDefault, TestTypeProvider> = function (instance, opts, done) { }
79
+ const testPluginWithTypeProviderAsync: FastifyPluginAsync<TestOptions, RawServerDefault, TestTypeProvider> = async function (instance, opts) { }
80
+ const testPluginWithTypeProviderWithType = (instance: ServerWithTypeProvider, opts: FastifyPluginOptions, done: (error?: FastifyError) => void) => { }
81
+ const testPluginWithTypeProviderWithTypeAsync = async (instance: ServerWithTypeProvider, opts: FastifyPluginOptions) => { }
82
+ expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginCallback))
83
+ expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginAsync))
84
+ expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginOpts))
85
+ expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginOptsAsync))
86
+ expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginOptsWithType))
87
+ expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginOptsWithTypeAsync))
88
+ expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginWithTypeProvider))
89
+ expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginWithTypeProviderAsync))
90
+ expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginWithTypeProviderWithType))
91
+ expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginWithTypeProviderWithTypeAsync))
92
+ expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register((instance) => {
93
+ expectAssignable<FastifyInstance>(instance)
94
+ }))
95
+ expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register((instance: ServerWithTypeProvider) => {
96
+ expectAssignable<ServerWithTypeProvider>(instance)
97
+ }))
98
+ expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(async (instance) => {
99
+ expectAssignable<FastifyInstance>(instance)
100
+ }))
101
+ expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(async (instance: ServerWithTypeProvider) => {
102
+ expectAssignable<ServerWithTypeProvider>(instance)
103
+ }))
@@ -49,7 +49,7 @@ interface RequestData extends RequestGenericInterface {
49
49
  type Handler = RouteHandler<RequestData>
50
50
 
51
51
  type CustomRequest = FastifyRequest<{
52
- Body: RequestBody;
52
+ Body: RequestBody | undefined;
53
53
  Querystring: RequestQuerystring;
54
54
  Params: RequestParams;
55
55
  Headers: RequestHeaders;
@@ -85,7 +85,7 @@ const getHandler: RouteHandler = function (request, _reply) {
85
85
  expectType<FastifyInstance>(request.server)
86
86
  }
87
87
 
88
- const getHandlerWithCustomLogger: RouteHandlerMethod<RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, RouteGenericInterface, ContextConfigDefault, FastifySchema, FastifyTypeProviderDefault, ResolveFastifyReplyReturnType<FastifyTypeProviderDefault, FastifySchema, RouteGenericInterface>, ResolveFastifyRequestType<FastifyTypeProviderDefault, FastifySchema, RouteGenericInterface>, CustomLoggerInterface> = function (request, _reply) {
88
+ const getHandlerWithCustomLogger: RouteHandlerMethod<RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, RouteGenericInterface, ContextConfigDefault, FastifySchema, FastifyTypeProviderDefault, ResolveFastifyRequestType<FastifyTypeProviderDefault, FastifySchema, RouteGenericInterface>, CustomLoggerInterface> = function (request, _reply) {
89
89
  expectType<CustomLoggerInterface>(request.log)
90
90
  }
91
91
 
@@ -104,11 +104,15 @@ const postHandler: Handler = function (request) {
104
104
  }
105
105
 
106
106
  function putHandler (request: CustomRequest, reply: FastifyReply) {
107
- expectType<RequestBody>(request.body)
107
+ expectType<RequestBody | undefined>(request.body)
108
108
  expectType<RequestParams>(request.params)
109
109
  expectType<RequestHeaders & RawRequestDefaultExpression['headers']>(request.headers)
110
110
  expectType<RequestQuerystring>(request.query)
111
- expectType<string>(request.body.content)
111
+ if (typeof request.body === 'undefined') {
112
+ expectType<undefined>(request.body)
113
+ } else {
114
+ expectType<string>(request.body.content)
115
+ }
112
116
  expectType<string>(request.query.from)
113
117
  expectType<number>(request.params.id)
114
118
  expectType<string>(request.headers['x-foobar'])
@@ -298,7 +298,7 @@ expectError(server.withTypeProvider<TypeBoxProvider>().get(
298
298
  }
299
299
  }
300
300
  },
301
- async (_, res): Promise<RouteHandlerMethod<RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, RouteGenericInterface, ContextConfigDefault, FastifySchema, TypeBoxProvider>> => {
301
+ async (_, res) => {
302
302
  return false
303
303
  }
304
304
  ))
@@ -384,11 +384,20 @@ expectError(server.withTypeProvider<JsonSchemaToTsProvider>().get(
384
384
  } as const
385
385
  }
386
386
  },
387
- async (_, res): Promise<RouteHandlerMethod<RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, RouteGenericInterface, ContextConfigDefault, FastifySchema, TypeBoxProvider>> => {
387
+ async (_, res) => {
388
388
  return false
389
389
  }
390
390
  ))
391
391
 
392
+ // https://github.com/fastify/fastify/issues/4088
393
+ expectError(server.withTypeProvider<JsonSchemaToTsProvider>().get('/', {
394
+ schema: {
395
+ response: { type: 'string' }
396
+ } as const
397
+ }, (_, res) => {
398
+ return { foo: 555 }
399
+ }))
400
+
392
401
  // -------------------------------------------------------------------
393
402
  // Reply Type Override
394
403
  // -------------------------------------------------------------------
@@ -97,6 +97,38 @@ test('should be able to use setErrorHandler specify custom validation error', t
97
97
  })
98
98
  })
99
99
 
100
+ test('validation error has 400 statusCode set', t => {
101
+ t.plan(3)
102
+
103
+ const fastify = Fastify()
104
+
105
+ fastify.setErrorHandler((error, request, reply) => {
106
+ const errorResponse = {
107
+ message: error.message,
108
+ statusCode: error.statusCode || 500
109
+ }
110
+
111
+ reply.code(errorResponse.statusCode).send(errorResponse)
112
+ })
113
+
114
+ fastify.post('/', { schema }, echoBody)
115
+
116
+ fastify.inject({
117
+ method: 'POST',
118
+ payload: {
119
+ hello: 'michelangelo'
120
+ },
121
+ url: '/'
122
+ }, (err, res) => {
123
+ t.error(err)
124
+ t.same(res.json(), {
125
+ statusCode: 400,
126
+ message: "body must have required property 'name'"
127
+ })
128
+ t.equal(res.statusCode, 400)
129
+ })
130
+ })
131
+
100
132
  test('error inside custom error handler should have validationContext', t => {
101
133
  t.plan(1)
102
134
 
@@ -1,6 +1,8 @@
1
1
  import { FastifyPluginOptions, FastifyPluginCallback, FastifyPluginAsync } from './plugin'
2
2
  import { LogLevel } from './logger'
3
3
  import { FastifyInstance } from './instance'
4
+ import { RawServerBase } from './utils'
5
+ import { FastifyTypeProvider, RawServerDefault } from '../fastify'
4
6
 
5
7
  export interface RegisterOptions {
6
8
  prefix?: string;
@@ -15,17 +17,17 @@ export type FastifyRegisterOptions<Options> = (RegisterOptions & Options) | ((in
15
17
  *
16
18
  * Function for adding a plugin to fastify. The options are inferred from the passed in FastifyPlugin parameter.
17
19
  */
18
- export interface FastifyRegister<T = void> {
19
- <Options extends FastifyPluginOptions>(
20
- plugin: FastifyPluginCallback<Options>,
20
+ export interface FastifyRegister<T = void, RawServer extends RawServerBase = RawServerDefault, TypeProviderDefault extends FastifyTypeProvider = FastifyTypeProvider> {
21
+ <Options extends FastifyPluginOptions, Server extends RawServerBase = RawServer, TypeProvider extends FastifyTypeProvider = TypeProviderDefault>(
22
+ plugin: FastifyPluginCallback<Options, Server, TypeProvider>,
21
23
  opts?: FastifyRegisterOptions<Options>
22
24
  ): T;
23
- <Options extends FastifyPluginOptions>(
24
- plugin: FastifyPluginAsync<Options>,
25
+ <Options extends FastifyPluginOptions, Server extends RawServerBase = RawServer, TypeProvider extends FastifyTypeProvider = TypeProviderDefault>(
26
+ plugin: FastifyPluginAsync<Options, Server, TypeProvider>,
25
27
  opts?: FastifyRegisterOptions<Options>
26
28
  ): T;
27
- <Options extends FastifyPluginOptions>(
28
- plugin: FastifyPluginCallback<Options> | FastifyPluginAsync<Options> | Promise<{ default: FastifyPluginCallback<Options> }> | Promise<{ default: FastifyPluginAsync<Options> }>,
29
+ <Options extends FastifyPluginOptions, Server extends RawServerBase = RawServer, TypeProvider extends FastifyTypeProvider = TypeProviderDefault>(
30
+ plugin: FastifyPluginCallback<Options, Server, TypeProvider> | FastifyPluginAsync<Options, Server, TypeProvider> | Promise<{ default: FastifyPluginCallback<Options, Server, TypeProvider> }> | Promise<{ default: FastifyPluginAsync<Options, Server, TypeProvider> }>,
29
31
  opts?: FastifyRegisterOptions<Options>
30
32
  ): T;
31
33
  }
package/types/route.d.ts CHANGED
@@ -69,14 +69,14 @@ export type RouteHandlerMethod<
69
69
  ContextConfig = ContextConfigDefault,
70
70
  SchemaCompiler extends FastifySchema = FastifySchema,
71
71
  TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
72
- ReturnType = ResolveFastifyReplyReturnType<TypeProvider, SchemaCompiler, RouteGeneric>,
73
72
  RequestType extends FastifyRequestType = ResolveFastifyRequestType<TypeProvider, SchemaCompiler, RouteGeneric>,
74
73
  Logger extends FastifyLoggerInstance = FastifyLoggerInstance
75
74
  > = (
76
75
  this: FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider>,
77
76
  request: FastifyRequest<RouteGeneric, RawServer, RawRequest, SchemaCompiler, TypeProvider, ContextConfig, RequestType, Logger>,
78
77
  reply: FastifyReply<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider>
79
- ) => ReturnType
78
+ // This return type used to be a generic type argument. Due to TypeScript's inference of return types, this rendered returns unchecked.
79
+ ) => ResolveFastifyReplyReturnType<TypeProvider, SchemaCompiler, RouteGeneric>
80
80
 
81
81
  /**
82
82
  * Shorthand options including the handler function property
@@ -89,11 +89,10 @@ export interface RouteShorthandOptionsWithHandler<
89
89
  ContextConfig = ContextConfigDefault,
90
90
  SchemaCompiler = FastifySchema,
91
91
  TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
92
- ReturnType = ResolveFastifyReplyReturnType<TypeProvider, SchemaCompiler, RouteGeneric>,
93
92
  RequestType extends FastifyRequestType = ResolveFastifyRequestType<TypeProvider, SchemaCompiler, RouteGeneric>,
94
93
  Logger extends FastifyLoggerInstance = FastifyLoggerInstance
95
94
  > extends RouteShorthandOptions<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, RequestType, Logger> {
96
- handler: RouteHandlerMethod<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, ReturnType, RequestType, Logger>;
95
+ handler: RouteHandlerMethod<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, RequestType, Logger>;
97
96
  }
98
97
 
99
98
  /**
@@ -105,18 +104,18 @@ export interface RouteShorthandMethod<
105
104
  RawReply extends RawReplyDefaultExpression<RawServer> = RawReplyDefaultExpression<RawServer>,
106
105
  TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
107
106
  > {
108
- <RouteGeneric extends RouteGenericInterface = RouteGenericInterface, ContextConfig = ContextConfigDefault, SchemaCompiler = FastifySchema, ReturnType = ResolveFastifyReplyReturnType<TypeProvider, SchemaCompiler, RouteGeneric>, RequestType extends FastifyRequestType = ResolveFastifyRequestType<TypeProvider, SchemaCompiler, RouteGeneric>, Logger extends FastifyLoggerInstance = FastifyLoggerInstance>(
107
+ <RouteGeneric extends RouteGenericInterface = RouteGenericInterface, ContextConfig = ContextConfigDefault, SchemaCompiler = FastifySchema, RequestType extends FastifyRequestType = ResolveFastifyRequestType<TypeProvider, SchemaCompiler, RouteGeneric>, Logger extends FastifyLoggerInstance = FastifyLoggerInstance>(
109
108
  path: string,
110
109
  opts: RouteShorthandOptions<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, RequestType, Logger>,
111
- handler: RouteHandlerMethod<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, ReturnType, RequestType, Logger>
110
+ handler: RouteHandlerMethod<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, RequestType, Logger>
112
111
  ): FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider>;
113
- <RouteGeneric extends RouteGenericInterface = RouteGenericInterface, ContextConfig = ContextConfigDefault, SchemaCompiler = FastifySchema, ReturnType = ResolveFastifyReplyReturnType<TypeProvider, SchemaCompiler, RouteGeneric>, RequestType extends FastifyRequestType = ResolveFastifyRequestType<TypeProvider, SchemaCompiler, RouteGeneric>, Logger extends FastifyLoggerInstance = FastifyLoggerInstance>(
112
+ <RouteGeneric extends RouteGenericInterface = RouteGenericInterface, ContextConfig = ContextConfigDefault, SchemaCompiler = FastifySchema, RequestType extends FastifyRequestType = ResolveFastifyRequestType<TypeProvider, SchemaCompiler, RouteGeneric>, Logger extends FastifyLoggerInstance = FastifyLoggerInstance>(
114
113
  path: string,
115
- handler: RouteHandlerMethod<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, ReturnType, RequestType, Logger>
114
+ handler: RouteHandlerMethod<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, RequestType, Logger>
116
115
  ): FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider>;
117
- <RouteGeneric extends RouteGenericInterface = RouteGenericInterface, ContextConfig = ContextConfigDefault, SchemaCompiler = FastifySchema, ReturnType = ResolveFastifyReplyReturnType<TypeProvider, SchemaCompiler, RouteGeneric>, RequestType extends FastifyRequestType = ResolveFastifyRequestType<TypeProvider, SchemaCompiler, RouteGeneric>, Logger extends FastifyLoggerInstance = FastifyLoggerInstance>(
116
+ <RouteGeneric extends RouteGenericInterface = RouteGenericInterface, ContextConfig = ContextConfigDefault, SchemaCompiler = FastifySchema, RequestType extends FastifyRequestType = ResolveFastifyRequestType<TypeProvider, SchemaCompiler, RouteGeneric>, Logger extends FastifyLoggerInstance = FastifyLoggerInstance>(
118
117
  path: string,
119
- opts: RouteShorthandOptionsWithHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, ReturnType, RequestType, Logger>
118
+ opts: RouteShorthandOptionsWithHandler<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, RequestType, Logger>
120
119
  ): FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider>;
121
120
  }
122
121
 
@@ -131,13 +130,12 @@ export interface RouteOptions<
131
130
  ContextConfig = ContextConfigDefault,
132
131
  SchemaCompiler = FastifySchema,
133
132
  TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
134
- ReturnType = ResolveFastifyReplyReturnType<TypeProvider, SchemaCompiler, RouteGeneric>,
135
133
  RequestType extends FastifyRequestType = ResolveFastifyRequestType<TypeProvider, SchemaCompiler, RouteGeneric>,
136
134
  Logger extends FastifyLoggerInstance = FastifyLoggerInstance
137
135
  > extends RouteShorthandOptions<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, RequestType, Logger> {
138
136
  method: HTTPMethods | HTTPMethods[];
139
137
  url: string;
140
- handler: RouteHandlerMethod<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, ReturnType, RequestType, Logger>;
138
+ handler: RouteHandlerMethod<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, RequestType, Logger>;
141
139
  }
142
140
 
143
141
  export type RouteHandler<
package/types/schema.d.ts CHANGED
@@ -41,7 +41,7 @@ export type FastifySerializerCompiler<T> = (routeSchema: FastifyRouteSchemaDef<T
41
41
 
42
42
  export interface FastifySchemaControllerOptions{
43
43
  bucket?: (parentSchemas?: unknown) => {
44
- addSchema(schema: unknown): FastifyInstance;
44
+ add(schema: unknown): FastifyInstance;
45
45
  getSchema(schemaId: string): unknown;
46
46
  getSchemas(): Record<string, unknown>;
47
47
  };
@@ -21,17 +21,24 @@ export type CallTypeProvider<F extends FastifyTypeProvider, I> = (F & { input: I
21
21
  // -----------------------------------------------------------------------------------------------
22
22
 
23
23
  // Used to map undefined SchemaCompiler properties to unknown
24
- type UndefinedToUnknown<T> = T extends undefined ? unknown : T
24
+ // Without brackets, UndefinedToUnknown<undefined | null> => unknown
25
+ type UndefinedToUnknown<T> = [T] extends [undefined] ? unknown : T
26
+
27
+ // union-aware keyof operator
28
+ // keyof ({ a: number} | { b: number}) => never
29
+ // KeysOf<{a: number} | {b: number}> => "a" | "b"
30
+ // this exists to allow users to override faulty type-provider logic.
31
+ type KeysOf<T> = T extends any ? keyof T : never
25
32
 
26
33
  // Resolves Request types either from generic argument or Type Provider.
27
34
  type ResolveRequestParams<TypeProvider extends FastifyTypeProvider, SchemaCompiler extends FastifySchema, RouteGeneric extends RouteGenericInterface> =
28
- UndefinedToUnknown<keyof RouteGeneric['Params'] extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['params']> : RouteGeneric['Params']>
35
+ UndefinedToUnknown<KeysOf<RouteGeneric['Params']> extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['params']> : RouteGeneric['Params']>
29
36
  type ResolveRequestQuerystring<TypeProvider extends FastifyTypeProvider, SchemaCompiler extends FastifySchema, RouteGeneric extends RouteGenericInterface> =
30
- UndefinedToUnknown<keyof RouteGeneric['Querystring'] extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['querystring']> : RouteGeneric['Querystring']>
37
+ UndefinedToUnknown<KeysOf<RouteGeneric['Querystring']> extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['querystring']> : RouteGeneric['Querystring']>
31
38
  type ResolveRequestHeaders<TypeProvider extends FastifyTypeProvider, SchemaCompiler extends FastifySchema, RouteGeneric extends RouteGenericInterface> =
32
- UndefinedToUnknown<keyof RouteGeneric['Headers'] extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['headers']> : RouteGeneric['Headers']>
39
+ UndefinedToUnknown<KeysOf<RouteGeneric['Headers']> extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['headers']> : RouteGeneric['Headers']>
33
40
  type ResolveRequestBody<TypeProvider extends FastifyTypeProvider, SchemaCompiler extends FastifySchema, RouteGeneric extends RouteGenericInterface> =
34
- UndefinedToUnknown<keyof RouteGeneric['Body'] extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['body']> : RouteGeneric['Body']>
41
+ UndefinedToUnknown<KeysOf<RouteGeneric['Body']> extends never ? CallTypeProvider<TypeProvider, SchemaCompiler['body']> : RouteGeneric['Body']>
35
42
 
36
43
  // The target request type. This type is inferenced on fastify 'requests' via generic argument assignment
37
44
  export interface FastifyRequestType<Params = unknown, Querystring = unknown, Headers = unknown, Body = unknown> {