fastify 5.8.4 → 5.9.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 (105) hide show
  1. package/SECURITY.md +1 -1
  2. package/SPONSORS.md +6 -4
  3. package/docs/Guides/Database.md +0 -28
  4. package/docs/Guides/Ecosystem.md +17 -2
  5. package/docs/Guides/Serverless.md +2 -2
  6. package/docs/Guides/Write-Plugin.md +1 -1
  7. package/docs/Reference/Encapsulation.md +27 -26
  8. package/docs/Reference/Errors.md +10 -4
  9. package/docs/Reference/HTTP2.md +10 -10
  10. package/docs/Reference/Hooks.md +4 -4
  11. package/docs/Reference/Index.md +14 -16
  12. package/docs/Reference/LTS.md +12 -13
  13. package/docs/Reference/Lifecycle.md +9 -8
  14. package/docs/Reference/Logging.md +44 -39
  15. package/docs/Reference/Middleware.md +21 -25
  16. package/docs/Reference/Principles.md +2 -2
  17. package/docs/Reference/Reply.md +6 -1
  18. package/docs/Reference/Request.md +27 -16
  19. package/docs/Reference/Routes.md +5 -2
  20. package/docs/Reference/Server.md +31 -3
  21. package/docs/Reference/Type-Providers.md +29 -5
  22. package/docs/Reference/Validation-and-Serialization.md +15 -2
  23. package/docs/Reference/Warnings.md +7 -6
  24. package/eslint.config.js +7 -2
  25. package/fastify.d.ts +8 -3
  26. package/fastify.js +43 -14
  27. package/lib/content-type-parser.js +13 -1
  28. package/lib/decorate.js +11 -3
  29. package/lib/error-handler.js +4 -3
  30. package/lib/error-serializer.js +59 -59
  31. package/lib/errors.js +16 -1
  32. package/lib/four-oh-four.js +14 -9
  33. package/lib/handle-request.js +11 -5
  34. package/lib/plugin-override.js +2 -1
  35. package/lib/plugin-utils.js +5 -5
  36. package/lib/reply.js +63 -8
  37. package/lib/request.js +23 -19
  38. package/lib/route.js +20 -6
  39. package/lib/schema-controller.js +1 -1
  40. package/lib/schemas.js +37 -30
  41. package/lib/symbols.js +3 -1
  42. package/lib/validation.js +1 -13
  43. package/lib/warnings.js +3 -3
  44. package/package.json +16 -18
  45. package/scripts/validate-ecosystem-links.js +1 -0
  46. package/test/bundler/esbuild/package.json +1 -1
  47. package/test/close-pipelining.test.js +1 -2
  48. package/test/custom-http-server.test.js +38 -0
  49. package/test/decorator-instance-properties.test.js +63 -0
  50. package/test/diagnostics-channel/async-error-handler.test.js +74 -0
  51. package/test/hooks.test.js +23 -0
  52. package/test/http-methods/get.test.js +1 -1
  53. package/test/http2/plain.test.js +135 -0
  54. package/test/http2/secure-with-fallback.test.js +1 -1
  55. package/test/https/https.test.js +1 -2
  56. package/test/internals/errors.test.js +31 -1
  57. package/test/internals/plugin.test.js +3 -1
  58. package/test/internals/request.test.js +27 -3
  59. package/test/internals/schema-controller-perf.test.js +33 -0
  60. package/test/logger/logging.test.js +18 -1
  61. package/test/logger/options.test.js +38 -1
  62. package/test/reply-error.test.js +1 -1
  63. package/test/reply-trailers.test.js +70 -0
  64. package/test/request-media-type.test.js +105 -0
  65. package/test/request-port.test.js +72 -0
  66. package/test/route-prefix.test.js +34 -0
  67. package/test/router-options.test.js +222 -11
  68. package/test/schema-serialization.test.js +108 -0
  69. package/test/schema-validation.test.js +45 -0
  70. package/test/scripts/validate-ecosystem-links.test.js +40 -57
  71. package/test/throw.test.js +14 -0
  72. package/test/trust-proxy.test.js +74 -0
  73. package/test/types/content-type-parser.tst.ts +70 -0
  74. package/test/types/{decorate-request-reply.test-d.ts → decorate-request-reply.tst.ts} +4 -4
  75. package/test/types/{dummy-plugin.ts → dummy-plugin.mts} +1 -1
  76. package/test/types/errors.tst.ts +91 -0
  77. package/test/types/fastify.tst.ts +351 -0
  78. package/test/types/hooks.tst.ts +578 -0
  79. package/test/types/instance.tst.ts +597 -0
  80. package/test/types/{logger.test-d.ts → logger.tst.ts} +61 -62
  81. package/test/types/plugin.tst.ts +96 -0
  82. package/test/types/register.tst.ts +245 -0
  83. package/test/types/reply.tst.ts +297 -0
  84. package/test/types/request.tst.ts +199 -0
  85. package/test/types/route.tst.ts +576 -0
  86. package/test/types/{schema.test-d.ts → schema.tst.ts} +22 -22
  87. package/test/types/{serverFactory.test-d.ts → serverFactory.tst.ts} +4 -4
  88. package/test/types/tsconfig.json +9 -0
  89. package/test/types/{type-provider.test-d.ts → type-provider.tst.ts} +256 -250
  90. package/test/types/using.tst.ts +14 -0
  91. package/types/errors.d.ts +3 -0
  92. package/types/request.d.ts +23 -2
  93. package/AGENTS.md +0 -290
  94. package/test/types/content-type-parser.test-d.ts +0 -72
  95. package/test/types/errors.test-d.ts +0 -90
  96. package/test/types/fastify.test-d.ts +0 -352
  97. package/test/types/hooks.test-d.ts +0 -550
  98. package/test/types/import.ts +0 -2
  99. package/test/types/instance.test-d.ts +0 -588
  100. package/test/types/plugin.test-d.ts +0 -97
  101. package/test/types/register.test-d.ts +0 -237
  102. package/test/types/reply.test-d.ts +0 -254
  103. package/test/types/request.test-d.ts +0 -188
  104. package/test/types/route.test-d.ts +0 -553
  105. package/test/types/using.test-d.ts +0 -17
@@ -1,237 +0,0 @@
1
- import { expectAssignable, expectError, expectType } from 'tsd'
2
- import { IncomingMessage, Server, ServerResponse } from 'node:http'
3
- import { Http2Server, Http2ServerRequest, Http2ServerResponse } from 'node:http2'
4
- import fastify, { FastifyInstance, FastifyError, FastifyBaseLogger, FastifyPluginAsync, FastifyPluginCallback, FastifyPluginOptions, RawServerDefault } from '../../fastify'
5
-
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 = (
13
- instance: FastifyInstance,
14
- opts: FastifyPluginOptions,
15
- done: (error?: FastifyError) => void
16
- ) => { }
17
- const testPluginOptsWithTypeAsync = async (instance: FastifyInstance, opts: FastifyPluginOptions) => { }
18
-
19
- interface TestOptions extends FastifyPluginOptions {
20
- option1: string;
21
- option2: boolean;
22
- }
23
-
24
- // Type validation
25
- expectError(fastify().register(testPluginOptsAsync, { prefix: 1 }))
26
- expectError(fastify().register(testPluginOptsAsync, { logLevel: () => ({}) }))
27
- expectError(fastify().register(testPluginOptsAsync, { logSerializers: () => ({}) }))
28
- expectError(fastify().register({}))
29
-
30
- expectAssignable<FastifyInstance>(
31
- fastify().register(
32
- testPluginOptsAsync, { prefix: '/example', logLevel: 'info', logSerializers: { key: (value: any) => `${value}` } }
33
- )
34
- )
35
-
36
- expectAssignable<FastifyInstance>(
37
- fastify().register(testPluginOptsAsync, () => {
38
- return {}
39
- })
40
- )
41
-
42
- expectAssignable<FastifyInstance>(
43
- fastify().register(testPluginOptsAsync, (instance) => {
44
- expectType<FastifyInstance>(instance)
45
- })
46
- )
47
-
48
- // With Http2
49
- const serverWithHttp2 = fastify({ http2: true })
50
- type ServerWithHttp2 = FastifyInstance<Http2Server, Http2ServerRequest, Http2ServerResponse>
51
- const testPluginWithHttp2: FastifyPluginCallback<TestOptions, Http2Server> = function (instance, opts, done) { }
52
- const testPluginWithHttp2Async: FastifyPluginAsync<TestOptions, Http2Server> = async function (instance, opts) { }
53
- const testPluginWithHttp2WithType = (
54
- instance: ServerWithHttp2,
55
- opts: FastifyPluginOptions,
56
- done: (error?: FastifyError) => void
57
- ) => { }
58
- const testPluginWithHttp2WithTypeAsync = async (
59
- instance: ServerWithHttp2,
60
- opts: FastifyPluginOptions
61
- ) => { }
62
- const testOptions: TestOptions = {
63
- option1: 'a',
64
- option2: false
65
- }
66
- expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginCallback))
67
- expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginAsync))
68
- expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginOpts))
69
- expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginOptsAsync))
70
- expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginOptsWithType))
71
- expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginOptsWithTypeAsync))
72
- // @ts-expect-error
73
- serverWithHttp2.register(testPluginWithHttp2)
74
- expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginWithHttp2, testOptions))
75
- // @ts-expect-error
76
- serverWithHttp2.register(testPluginWithHttp2Async)
77
- expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginWithHttp2Async, testOptions))
78
- expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginWithHttp2WithType))
79
- expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginWithHttp2WithTypeAsync))
80
- expectAssignable<ServerWithHttp2>(serverWithHttp2.register((instance) => {
81
- expectAssignable<FastifyInstance>(instance)
82
- }))
83
- expectAssignable<ServerWithHttp2>(serverWithHttp2.register((instance: ServerWithHttp2) => {
84
- expectAssignable<ServerWithHttp2>(instance)
85
- }))
86
- expectAssignable<ServerWithHttp2>(serverWithHttp2.register(async (instance) => {
87
- expectAssignable<FastifyInstance>(instance)
88
- }))
89
- expectAssignable<ServerWithHttp2>(serverWithHttp2.register(async (instance: ServerWithHttp2) => {
90
- expectAssignable<ServerWithHttp2>(instance)
91
- }))
92
-
93
- // With Type Provider
94
- type TestTypeProvider = { schema: 'test', validator: 'test', serializer: 'test' }
95
- const serverWithTypeProvider = fastify().withTypeProvider<TestTypeProvider>()
96
- type ServerWithTypeProvider = FastifyInstance<
97
- Server,
98
- IncomingMessage,
99
- ServerResponse,
100
- FastifyBaseLogger,
101
- TestTypeProvider
102
- >
103
- const testPluginWithTypeProvider: FastifyPluginCallback<
104
- TestOptions,
105
- RawServerDefault,
106
- TestTypeProvider
107
- > = function (instance, opts, done) { }
108
- const testPluginWithTypeProviderAsync: FastifyPluginAsync<
109
- TestOptions,
110
- RawServerDefault,
111
- TestTypeProvider
112
- > = async function (instance, opts) { }
113
- const testPluginWithTypeProviderWithType = (
114
- instance: ServerWithTypeProvider,
115
- opts: FastifyPluginOptions,
116
- done: (error?: FastifyError) => void
117
- ) => { }
118
- const testPluginWithTypeProviderWithTypeAsync = async (
119
- instance: ServerWithTypeProvider,
120
- opts: FastifyPluginOptions
121
- ) => { }
122
- expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginCallback))
123
- expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginAsync))
124
- expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginOpts))
125
- expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginOptsAsync))
126
- expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginOptsWithType))
127
- expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginOptsWithTypeAsync))
128
- // @ts-expect-error
129
- serverWithTypeProvider.register(testPluginWithTypeProvider)
130
- expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginWithTypeProvider, testOptions))
131
- // @ts-expect-error
132
- serverWithTypeProvider.register(testPluginWithTypeProviderAsync)
133
- expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginWithTypeProviderAsync, testOptions))
134
- expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginWithTypeProviderWithType))
135
- expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginWithTypeProviderWithTypeAsync))
136
- expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register((instance) => {
137
- expectAssignable<FastifyInstance>(instance)
138
- }))
139
- expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register((instance: ServerWithTypeProvider) => {
140
- expectAssignable<ServerWithTypeProvider>(instance)
141
- }))
142
- expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(async (instance) => {
143
- expectAssignable<FastifyInstance>(instance)
144
- }))
145
- expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(async (instance: ServerWithTypeProvider) => {
146
- expectAssignable<ServerWithTypeProvider>(instance)
147
- }))
148
-
149
- // With Type Provider and logger
150
- const customLogger = {
151
- level: 'info',
152
- info: () => { },
153
- warn: () => { },
154
- error: () => { },
155
- fatal: () => { },
156
- trace: () => { },
157
- debug: () => { },
158
- child: () => customLogger,
159
- silent: () => { }
160
- }
161
- const serverWithTypeProviderAndLogger = fastify({
162
- loggerInstance: customLogger
163
- }).withTypeProvider<TestTypeProvider>()
164
- type ServerWithTypeProviderAndLogger = FastifyInstance<
165
- Server,
166
- IncomingMessage,
167
- ServerResponse,
168
- typeof customLogger,
169
- TestTypeProvider
170
- >
171
- const testPluginWithTypeProviderAndLogger: FastifyPluginCallback<
172
- TestOptions,
173
- RawServerDefault,
174
- TestTypeProvider,
175
- typeof customLogger
176
- > = function (instance, opts, done) { }
177
- const testPluginWithTypeProviderAndLoggerAsync: FastifyPluginAsync<
178
- TestOptions,
179
- RawServerDefault,
180
- TestTypeProvider,
181
- typeof customLogger
182
- > = async function (instance, opts) { }
183
- const testPluginWithTypeProviderAndLoggerWithType = (
184
- instance: ServerWithTypeProviderAndLogger,
185
- opts: FastifyPluginOptions,
186
- done: (error?: FastifyError) => void
187
- ) => { }
188
- const testPluginWithTypeProviderAndLoggerWithTypeAsync = async (
189
- instance: ServerWithTypeProviderAndLogger,
190
- opts: FastifyPluginOptions
191
- ) => { }
192
- expectAssignable<ServerWithTypeProviderAndLogger>(serverWithTypeProviderAndLogger.register(testPluginCallback))
193
- expectAssignable<ServerWithTypeProviderAndLogger>(serverWithTypeProviderAndLogger.register(testPluginAsync))
194
- expectAssignable<ServerWithTypeProviderAndLogger>(serverWithTypeProviderAndLogger.register(testPluginOpts))
195
- expectAssignable<ServerWithTypeProviderAndLogger>(serverWithTypeProviderAndLogger.register(testPluginOptsAsync))
196
- expectAssignable<ServerWithTypeProviderAndLogger>(serverWithTypeProviderAndLogger.register(testPluginOptsWithType))
197
- expectAssignable<ServerWithTypeProviderAndLogger>(serverWithTypeProviderAndLogger.register(testPluginOptsWithTypeAsync))
198
- expectAssignable<ServerWithTypeProviderAndLogger>(
199
- // @ts-expect-error
200
- serverWithTypeProviderAndLogger.register(testPluginWithTypeProviderAndLogger)
201
- )
202
- expectAssignable<ServerWithTypeProviderAndLogger>(
203
- serverWithTypeProviderAndLogger.register(testPluginWithTypeProviderAndLogger, testOptions)
204
- )
205
- expectAssignable<ServerWithTypeProviderAndLogger>(
206
- // @ts-expect-error
207
- serverWithTypeProviderAndLogger.register(testPluginWithTypeProviderAndLoggerAsync)
208
- )
209
- expectAssignable<ServerWithTypeProviderAndLogger>(
210
- serverWithTypeProviderAndLogger.register(testPluginWithTypeProviderAndLoggerAsync, testOptions)
211
- )
212
- expectAssignable<ServerWithTypeProviderAndLogger>(
213
- serverWithTypeProviderAndLogger.register(testPluginWithTypeProviderAndLoggerWithType)
214
- )
215
- expectAssignable<ServerWithTypeProviderAndLogger>(
216
- serverWithTypeProviderAndLogger.register(testPluginWithTypeProviderAndLoggerWithTypeAsync)
217
- )
218
- expectAssignable<ServerWithTypeProviderAndLogger>(
219
- serverWithTypeProviderAndLogger.register((instance) => {
220
- expectAssignable<FastifyInstance>(instance)
221
- })
222
- )
223
- expectAssignable<ServerWithTypeProviderAndLogger>(
224
- serverWithTypeProviderAndLogger.register((instance: ServerWithTypeProviderAndLogger) => {
225
- expectAssignable<ServerWithTypeProviderAndLogger>(instance)
226
- })
227
- )
228
- expectAssignable<ServerWithTypeProviderAndLogger>(
229
- serverWithTypeProviderAndLogger.register(async (instance) => {
230
- expectAssignable<FastifyInstance>(instance)
231
- })
232
- )
233
- expectAssignable<ServerWithTypeProviderAndLogger>(
234
- serverWithTypeProviderAndLogger.register(async (instance: ServerWithTypeProviderAndLogger) => {
235
- expectAssignable<ServerWithTypeProviderAndLogger>(instance)
236
- })
237
- )
@@ -1,254 +0,0 @@
1
- import { Buffer } from 'node:buffer'
2
- import { expectAssignable, expectError, expectType } from 'tsd'
3
- import fastify, { FastifyContextConfig, FastifyReply, FastifyRequest, FastifySchema, FastifyTypeProviderDefault, RawRequestDefaultExpression, RouteHandler, RouteHandlerMethod } from '../../fastify'
4
- import { FastifyInstance } from '../../types/instance'
5
- import { FastifyBaseLogger } from '../../types/logger'
6
- import { ResolveReplyTypeWithRouteGeneric } from '../../types/reply'
7
- import { FastifyRouteConfig, RouteGenericInterface } from '../../types/route'
8
- import { ContextConfigDefault, RawReplyDefaultExpression, RawServerDefault } from '../../types/utils'
9
-
10
- type DefaultSerializationFunction = (payload: { [key: string]: unknown }) => string
11
- type DefaultFastifyReplyWithCode<Code extends number> = FastifyReply<RouteGenericInterface, RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, ContextConfigDefault, FastifySchema, FastifyTypeProviderDefault, ResolveReplyTypeWithRouteGeneric<RouteGenericInterface['Reply'], Code, FastifySchema, FastifyTypeProviderDefault>>
12
-
13
- const getHandler: RouteHandlerMethod = function (_request, reply) {
14
- expectType<RawReplyDefaultExpression>(reply.raw)
15
- expectType<FastifyBaseLogger>(reply.log)
16
- expectType<FastifyRequest<RouteGenericInterface, RawServerDefault, RawRequestDefaultExpression>>(reply.request)
17
- expectType<<Code extends number>(statusCode: Code) => DefaultFastifyReplyWithCode<Code>>(reply.code)
18
- expectType<<Code extends number>(statusCode: Code) => DefaultFastifyReplyWithCode<Code>>(reply.status)
19
- expectType<(...args: [payload?: unknown]) => FastifyReply>(reply.code(100 as number).send)
20
- expectType<number>(reply.elapsedTime)
21
- expectType<number>(reply.statusCode)
22
- expectType<boolean>(reply.sent)
23
- expectType<
24
- (hints: Record<string, string | string[]>, callback?: (() => void) | undefined) => void
25
- >(reply.writeEarlyHints)
26
- expectType<((...args: [payload?: unknown]) => FastifyReply)>(reply.send)
27
- expectAssignable<(key: string, value: any) => FastifyReply>(reply.header)
28
- expectAssignable<(values: { [key: string]: any }) => FastifyReply>(reply.headers)
29
- expectAssignable<(key: string) => number | string | string[] | undefined>(reply.getHeader)
30
- expectAssignable<() => { [key: string]: number | string | string[] | undefined }>(reply.getHeaders)
31
- expectAssignable<(key: string) => FastifyReply>(reply.removeHeader)
32
- expectAssignable<(key: string) => boolean>(reply.hasHeader)
33
- expectType<(url: string, statusCode?: number) => FastifyReply>(reply.redirect)
34
- expectType<() => FastifyReply>(reply.hijack)
35
- expectType<() => void>(reply.callNotFound)
36
- expectType<(contentType: string) => FastifyReply>(reply.type)
37
- expectType<(fn: (payload: any) => string) => FastifyReply>(reply.serializer)
38
- expectType<(payload: any) => string | ArrayBuffer | Buffer>(reply.serialize)
39
- expectType<(fulfilled: () => void, rejected: (err: Error) => void) => void>(reply.then)
40
- expectType<
41
- (
42
- key: string,
43
- fn: ((reply: FastifyReply, payload: string | Buffer | null) => Promise<string>) |
44
- ((reply: FastifyReply, payload: string | Buffer | null,
45
- done: (err: Error | null, value?: string) => void) => void)
46
- ) => FastifyReply
47
- >(reply.trailer)
48
- expectType<(key: string) => boolean>(reply.hasTrailer)
49
- expectType<(key: string) => FastifyReply>(reply.removeTrailer)
50
- expectType<FastifyInstance>(reply.server)
51
- expectAssignable<
52
- ((httpStatus: string) => DefaultSerializationFunction | undefined)
53
- >(reply.getSerializationFunction)
54
- expectAssignable<
55
- ((schema: { [key: string]: unknown }) => DefaultSerializationFunction | undefined)
56
- >(reply.getSerializationFunction)
57
- expectAssignable<
58
- ((schema: { [key: string]: unknown }, httpStatus?: string) => DefaultSerializationFunction)
59
- >(reply.compileSerializationSchema)
60
- expectAssignable<
61
- ((input: { [key: string]: unknown }, schema: { [key: string]: unknown }, httpStatus?: string) => unknown)
62
- >(reply.serializeInput)
63
- expectAssignable<((input: { [key: string]: unknown }, httpStatus: string) => unknown)>(reply.serializeInput)
64
- expectType<ContextConfigDefault & FastifyRouteConfig & FastifyContextConfig>(reply.routeOptions.config)
65
- expectType<string>(reply.getDecorator<string>('foo'))
66
- }
67
-
68
- interface ReplyPayload {
69
- Reply: {
70
- test: boolean;
71
- };
72
- }
73
-
74
- interface ReplyArrayPayload {
75
- Reply: string[]
76
- }
77
-
78
- interface ReplyUnion {
79
- Reply: {
80
- success: boolean;
81
- } | {
82
- error: string;
83
- }
84
- }
85
-
86
- interface ReplyHttpCodes {
87
- Reply: {
88
- '1xx': number,
89
- 200: 'abc',
90
- 201: boolean,
91
- 300: { foo: string },
92
- }
93
- }
94
-
95
- interface InvalidReplyHttpCodes {
96
- Reply: {
97
- '1xx': number,
98
- 200: string,
99
- 999: boolean,
100
- }
101
- }
102
-
103
- interface ReplyVoid {
104
- Reply: void;
105
- }
106
-
107
- interface ReplyUndefined {
108
- Reply: undefined;
109
- }
110
-
111
- // Issue #5534 scenario: 204 No Content should allow empty send(), 201 Created should require payload
112
- // Note: `204: undefined` gets converted to `unknown` via UndefinedToUnknown in type-provider.d.ts,
113
- // meaning send() is optional but send({}) is also allowed. Use `void` instead of `undefined`
114
- // if you want stricter "no payload allowed" semantics.
115
- interface ReplyHttpCodesWithNoContent {
116
- Reply: {
117
- 201: { id: string };
118
- 204: undefined;
119
- }
120
- }
121
-
122
- const typedHandler: RouteHandler<ReplyPayload> = async (request, reply) => {
123
- // When Reply type is specified, send() requires a payload argument
124
- expectType<((...args: [payload: ReplyPayload['Reply']]) => FastifyReply<ReplyPayload, RawServerDefault, RawRequestDefaultExpression<RawServerDefault>, RawReplyDefaultExpression<RawServerDefault>>)>(reply.send)
125
- expectType<((...args: [payload: ReplyPayload['Reply']]) => FastifyReply<ReplyPayload, RawServerDefault, RawRequestDefaultExpression<RawServerDefault>, RawReplyDefaultExpression<RawServerDefault>>)>(reply.code(100).send)
126
- }
127
-
128
- const server = fastify()
129
- server.get('/get', getHandler)
130
- server.get('/typed', typedHandler)
131
- server.get<ReplyPayload>('/get-generic-send', async function handler (request, reply) {
132
- reply.send({ test: true })
133
- })
134
- // When Reply type is specified, send() requires a payload - calling without arguments should error
135
- expectError(server.get<ReplyPayload>('/get-generic-send-missing-payload', async function handler (request, reply) {
136
- reply.send()
137
- }))
138
- server.get<ReplyPayload>('/get-generic-return', async function handler (request, reply) {
139
- return { test: false }
140
- })
141
- expectError(server.get<ReplyPayload>('/get-generic-send-error', async function handler (request, reply) {
142
- reply.send({ foo: 'bar' })
143
- }))
144
- expectError(server.get<ReplyPayload>('/get-generic-return-error', async function handler (request, reply) {
145
- return { foo: 'bar' }
146
- }))
147
- server.get<ReplyUnion>('/get-generic-union-send', async function handler (request, reply) {
148
- if (0 as number === 0) {
149
- reply.send({ success: true })
150
- } else {
151
- reply.send({ error: 'error' })
152
- }
153
- })
154
- server.get<ReplyUnion>('/get-generic-union-return', async function handler (request, reply) {
155
- if (0 as number === 0) {
156
- return { success: true }
157
- } else {
158
- return { error: 'error' }
159
- }
160
- })
161
- expectError(server.get<ReplyUnion>('/get-generic-union-send-error-1', async function handler (request, reply) {
162
- reply.send({ successes: true })
163
- }))
164
- expectError(server.get<ReplyUnion>('/get-generic-union-send-error-2', async function handler (request, reply) {
165
- reply.send({ error: 500 })
166
- }))
167
- expectError(server.get<ReplyUnion>('/get-generic-union-return-error-1', async function handler (request, reply) {
168
- return { successes: true }
169
- }))
170
- expectError(server.get<ReplyUnion>('/get-generic-union-return-error-2', async function handler (request, reply) {
171
- return { error: 500 }
172
- }))
173
- server.get<ReplyHttpCodes>('/get-generic-http-codes-send', async function handler (request, reply) {
174
- reply.code(200).send('abc')
175
- reply.code(201).send(true)
176
- reply.code(300).send({ foo: 'bar' })
177
- reply.code(101).send(123)
178
- })
179
- expectError(server.get<ReplyHttpCodes>('/get-generic-http-codes-send-error-1', async function handler (request, reply) {
180
- reply.code(200).send('def')
181
- }))
182
- expectError(server.get<ReplyHttpCodes>('/get-generic-http-codes-send-error-2', async function handler (request, reply) {
183
- reply.code(201).send(0)
184
- }))
185
- expectError(server.get<ReplyHttpCodes>('/get-generic-http-codes-send-error-3', async function handler (request, reply) {
186
- reply.code(300).send({ foo: 123 })
187
- }))
188
- expectError(server.get<ReplyHttpCodes>('/get-generic-http-codes-send-error-4', async function handler (request, reply) {
189
- reply.code(100).send('asdasd')
190
- }))
191
- expectError(server.get<ReplyHttpCodes>('/get-generic-http-codes-send-error-5', async function handler (request, reply) {
192
- reply.code(401).send({ foo: 123 })
193
- }))
194
- server.get<ReplyArrayPayload>('/get-generic-array-send', async function handler (request, reply) {
195
- reply.code(200).send([''])
196
- })
197
- expectError(server.get<InvalidReplyHttpCodes>('get-invalid-http-codes-reply-error', async function handler (request, reply) {
198
- reply.code(200).send('')
199
- }))
200
- server.get<InvalidReplyHttpCodes>('get-invalid-http-codes-reply-error', async function handler (request, reply) {
201
- reply.code(200).send({
202
- '1xx': 0,
203
- 200: '',
204
- 999: false
205
- })
206
- })
207
-
208
- /* eslint-disable @typescript-eslint/no-unused-vars */
209
- const httpHeaderHandler: RouteHandlerMethod = function (_request, reply) {
210
- // accept is a header provided by @types/node
211
- reply.getHeader('accept')
212
- /* eslint-disable @typescript-eslint/no-unused-expressions */
213
- reply.getHeaders().accept
214
- reply.hasHeader('accept')
215
- reply.header('accept', 'test')
216
- reply.headers({ accept: 'test' })
217
- reply.removeHeader('accept')
218
-
219
- // x-fastify-test is not a header provided by @types/node
220
- // and should not result in a typing error
221
- reply.getHeader('x-fastify-test')
222
- reply.getHeaders()['x-fastify-test']
223
- reply.hasHeader('x-fastify-test')
224
- reply.header('x-fastify-test', 'test')
225
- reply.headers({ 'x-fastify-test': 'test' })
226
- reply.removeHeader('x-fastify-test')
227
- }
228
-
229
- // Test: send() without arguments is valid when no Reply type is specified (default unknown)
230
- server.get('/get-no-type-send-empty', async function handler (request, reply) {
231
- reply.send()
232
- })
233
-
234
- // Test: send() without arguments is valid when Reply type is void
235
- server.get<ReplyVoid>('/get-void-send-empty', async function handler (request, reply) {
236
- reply.send()
237
- })
238
-
239
- // Test: send() without arguments is valid when Reply type is undefined
240
- server.get<ReplyUndefined>('/get-undefined-send-empty', async function handler (request, reply) {
241
- reply.send()
242
- })
243
-
244
- // Issue #5534 scenario: HTTP status codes with 204 No Content
245
- server.get<ReplyHttpCodesWithNoContent>('/get-http-codes-no-content', async function handler (request, reply) {
246
- // 204 No Content - send() without payload is valid because Reply is undefined
247
- reply.code(204).send()
248
- // 201 Created - send() requires payload
249
- reply.code(201).send({ id: '123' })
250
- })
251
- // 201 Created without payload should error
252
- expectError(server.get<ReplyHttpCodesWithNoContent>('/get-http-codes-201-missing-payload', async function handler (request, reply) {
253
- reply.code(201).send()
254
- }))
@@ -1,188 +0,0 @@
1
- import { expectAssignable, expectError, expectType } from 'tsd'
2
- import fastify, {
3
- ContextConfigDefault,
4
- FastifyContextConfig,
5
- FastifyLogFn,
6
- FastifySchema,
7
- FastifyTypeProviderDefault,
8
- RawReplyDefaultExpression,
9
- RawRequestDefaultExpression,
10
- RawServerDefault,
11
- RequestBodyDefault,
12
- RequestGenericInterface,
13
- RouteHandler,
14
- RouteHandlerMethod,
15
- SafePromiseLike
16
- } from '../../fastify'
17
- import { FastifyInstance } from '../../types/instance'
18
- import { FastifyBaseLogger } from '../../types/logger'
19
- import { FastifyReply } from '../../types/reply'
20
- import { FastifyRequest, RequestRouteOptions } from '../../types/request'
21
- import { FastifyRouteConfig, RouteGenericInterface } from '../../types/route'
22
- import { RequestHeadersDefault, RequestParamsDefault, RequestQuerystringDefault } from '../../types/utils'
23
-
24
- interface RequestBody {
25
- content: string;
26
- }
27
-
28
- interface RequestQuerystring {
29
- from: string;
30
- }
31
-
32
- interface RequestParams {
33
- id: number;
34
- }
35
-
36
- interface RequestHeaders {
37
- 'x-foobar': string;
38
- }
39
-
40
- interface RequestData extends RequestGenericInterface {
41
- Body: RequestBody;
42
- Querystring: RequestQuerystring;
43
- Params: RequestParams;
44
- Headers: RequestHeaders;
45
- }
46
-
47
- type Handler = RouteHandler<RequestData>
48
-
49
- type CustomRequest = FastifyRequest<{
50
- Body: RequestBody | undefined;
51
- Querystring: RequestQuerystring;
52
- Params: RequestParams;
53
- Headers: RequestHeaders;
54
- }>
55
-
56
- type HTTPRequestPart = 'body' | 'query' | 'querystring' | 'params' | 'headers'
57
- type ExpectedGetValidationFunction = (input: { [key: string]: unknown }) => boolean
58
-
59
- interface CustomLoggerInterface extends FastifyBaseLogger {
60
- foo: FastifyLogFn; // custom severity logger method
61
- }
62
-
63
- const getHandler: RouteHandler = function (request, _reply) {
64
- expectType<string>(request.url)
65
- expectType<string>(request.originalUrl)
66
- expectType<string>(request.method)
67
- expectType<Readonly<RequestRouteOptions>>(request.routeOptions)
68
- expectType<boolean>(request.is404)
69
- expectType<string>(request.hostname)
70
- expectType<string>(request.host)
71
- expectType<number | null>(request.port)
72
- expectType<string>(request.ip)
73
- expectType<string[] | undefined>(request.ips)
74
- expectType<RawRequestDefaultExpression>(request.raw)
75
- expectType<RequestBodyDefault>(request.body)
76
- expectType<RequestParamsDefault>(request.params)
77
- expectType<ContextConfigDefault & FastifyRouteConfig & FastifyContextConfig>(request.routeOptions.config)
78
- expectType<FastifySchema | undefined>(request.routeOptions.schema)
79
- expectType<RouteHandlerMethod>(request.routeOptions.handler)
80
- expectType<string | undefined>(request.routeOptions.url)
81
- expectType<string | undefined>(request.routeOptions.version)
82
-
83
- expectType<RequestHeadersDefault & RawRequestDefaultExpression['headers']>(request.headers)
84
- request.headers = {}
85
-
86
- expectType<RequestQuerystringDefault>(request.query)
87
- expectType<string>(request.id)
88
- expectType<FastifyBaseLogger>(request.log)
89
- expectType<RawRequestDefaultExpression['socket']>(request.socket)
90
- expectType<AbortSignal>(request.signal)
91
- expectType<Error & { validation: any; validationContext: string } | undefined>(request.validationError)
92
- expectType<FastifyInstance>(request.server)
93
- expectAssignable<(httpPart: HTTPRequestPart) => ExpectedGetValidationFunction>(request.getValidationFunction)
94
- expectAssignable<(schema: { [key: string]: unknown }) => ExpectedGetValidationFunction>(request.getValidationFunction)
95
- expectAssignable<
96
- (input: { [key: string]: unknown }, schema: { [key: string]: unknown }, httpPart?: HTTPRequestPart) => boolean
97
- >(request.validateInput)
98
- expectAssignable<(input: { [key: string]: unknown }, httpPart?: HTTPRequestPart) => boolean>(request.validateInput)
99
- expectType<string>(request.getDecorator<string>('foo'))
100
- expectType<void>(request.setDecorator('foo', 'hello'))
101
- expectType<void>(request.setDecorator<string>('foo', 'hello'))
102
- expectError(request.setDecorator<string>('foo', true))
103
- }
104
-
105
- const getHandlerWithCustomLogger: RouteHandlerMethod<
106
- RawServerDefault,
107
- RawRequestDefaultExpression,
108
- RawReplyDefaultExpression,
109
- RouteGenericInterface,
110
- ContextConfigDefault,
111
- FastifySchema,
112
- FastifyTypeProviderDefault,
113
- CustomLoggerInterface
114
- > = function (request, _reply) {
115
- expectType<CustomLoggerInterface>(request.log)
116
- }
117
-
118
- const postHandler: Handler = function (request) {
119
- expectType<RequestBody>(request.body)
120
- expectType<RequestParams>(request.params)
121
- expectType<RequestHeaders & RawRequestDefaultExpression['headers']>(
122
- request.headers
123
- )
124
- expectType<RequestQuerystring>(request.query)
125
- expectType<string>(request.body.content)
126
- expectType<string>(request.query.from)
127
- expectType<number>(request.params.id)
128
- expectType<string>(request.headers['x-foobar'])
129
- expectType<FastifyInstance>(request.server)
130
- expectType<FastifyContextConfig & FastifyRouteConfig>(request.routeOptions.config)
131
- }
132
-
133
- function putHandler (request: CustomRequest, reply: FastifyReply) {
134
- expectType<RequestBody | undefined>(request.body)
135
- expectType<RequestParams>(request.params)
136
- expectType<RequestHeaders & RawRequestDefaultExpression['headers']>(request.headers)
137
- expectType<RequestQuerystring>(request.query)
138
- if (request.body === undefined) {
139
- expectType<undefined>(request.body)
140
- } else {
141
- expectType<string>(request.body.content)
142
- }
143
- expectType<string>(request.query.from)
144
- expectType<number>(request.params.id)
145
- expectType<string>(request.headers['x-foobar'])
146
- expectType<FastifyInstance>(request.server)
147
- expectType<ContextConfigDefault & FastifyRouteConfig & FastifyContextConfig>(request.routeOptions.config)
148
- }
149
-
150
- const server = fastify()
151
- server.get('/get', getHandler)
152
- server.post('/post', postHandler)
153
- server.put('/put', putHandler)
154
-
155
- const customLogger: CustomLoggerInterface = {
156
- level: 'info',
157
- silent: () => { },
158
- info: () => { },
159
- warn: () => { },
160
- error: () => { },
161
- fatal: () => { },
162
- trace: () => { },
163
- debug: () => { },
164
- foo: () => { }, // custom severity logger method
165
- child: () => customLogger
166
- }
167
-
168
- const serverWithCustomLogger = fastify({ loggerInstance: customLogger })
169
- expectError<
170
- FastifyInstance<RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, CustomLoggerInterface>
171
- & Promise<
172
- FastifyInstance<RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, CustomLoggerInterface>
173
- >
174
- >(serverWithCustomLogger)
175
- expectAssignable<
176
- FastifyInstance<RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, CustomLoggerInterface>
177
- & PromiseLike<
178
- FastifyInstance<RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, CustomLoggerInterface>
179
- >
180
- >(serverWithCustomLogger)
181
- expectType<
182
- FastifyInstance<RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, CustomLoggerInterface>
183
- & SafePromiseLike<
184
- FastifyInstance<RawServerDefault, RawRequestDefaultExpression, RawReplyDefaultExpression, CustomLoggerInterface>
185
- >
186
- >(serverWithCustomLogger)
187
-
188
- serverWithCustomLogger.get('/get', getHandlerWithCustomLogger)