fastify 6.0.0-alpha.4 → 6.0.0-alpha.6
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.
- package/README.md +1 -0
- package/SECURITY.md +6 -0
- package/build/build-validation.js +2 -0
- package/docs/Guides/Ecosystem.md +12 -53
- package/docs/Guides/Migration-Guide-V5.md +2 -2
- package/docs/Guides/Serverless.md +33 -10
- package/docs/Reference/Errors.md +13 -2
- package/docs/Reference/Hooks.md +13 -0
- package/docs/Reference/Reply.md +787 -681
- package/docs/Reference/Request.md +308 -104
- package/docs/Reference/Routes.md +6 -2
- package/docs/Reference/Server.md +41 -4
- package/docs/Reference/Validation-and-Serialization.md +48 -1
- package/docs/Reference/Warnings.md +2 -0
- package/fastify.d.ts +1 -0
- package/fastify.js +35 -1
- package/lib/config-validator.js +102 -73
- package/lib/content-type-parser.js +35 -14
- package/lib/content-type.js +4 -4
- package/lib/context.js +2 -1
- package/lib/decorate.js +4 -3
- package/lib/error-handler.js +21 -4
- package/lib/error-status.js +4 -2
- package/lib/errors.js +15 -14
- package/lib/handle-request.js +7 -20
- package/lib/reply.js +18 -13
- package/lib/request.js +12 -7
- package/lib/route.js +40 -7
- package/lib/schemas.js +44 -32
- package/lib/validation.js +67 -10
- package/lib/warnings.js +10 -1
- package/package.json +8 -3
- package/test/child-logger-factory.test.js +25 -0
- package/test/close-disposable.test.js +154 -0
- package/test/constrained-routes.test.js +4 -2
- package/test/content-parser.test.js +99 -0
- package/test/decorator.test.js +29 -0
- package/test/diagnostics-channel/error-status.test.js +35 -2
- package/test/handler-timeout.test.js +224 -0
- package/test/internals/all.test.js +5 -0
- package/test/internals/errors.test.js +19 -20
- package/test/internals/initial-config.test.js +2 -0
- package/test/internals/reply-serialize.test.js +20 -0
- package/test/internals/reply.test.js +30 -1
- package/test/internals/request.test.js +50 -0
- package/test/internals/server.test.js +6 -4
- package/test/reply-error.test.js +82 -0
- package/test/reply-media-type.test.js +57 -0
- package/test/reply-trailers.test.js +159 -1
- package/test/rfc-10008.test.js +6 -9
- package/test/router-compile.test.js +241 -0
- package/test/schema-feature.test.js +1 -1
- package/test/schema-serialization.test.js +120 -7
- package/test/schema-validation.test.js +251 -1
- package/test/types/errors.tst.ts +0 -1
- package/test/types/fastify.tst.ts +9 -0
- package/test/types/instance.tst.ts +1 -1
- package/test/types/route.tst.ts +37 -0
- package/test/types/using.tst.ts +20 -0
- package/test/validation-error-handling.test.js +21 -1
- package/types/errors.d.ts +0 -1
- package/types/instance.d.ts +9 -5
- package/types/route.d.ts +4 -2
|
@@ -3,6 +3,7 @@ import * as http from 'node:http'
|
|
|
3
3
|
import * as http2 from 'node:http2'
|
|
4
4
|
import * as https from 'node:https'
|
|
5
5
|
import { Socket } from 'node:net'
|
|
6
|
+
import pino from 'pino'
|
|
6
7
|
import { expect } from 'tstyche'
|
|
7
8
|
import fastify, {
|
|
8
9
|
ConnectionError,
|
|
@@ -180,6 +181,10 @@ const customLogger = {
|
|
|
180
181
|
debug: () => { },
|
|
181
182
|
child: () => customLogger
|
|
182
183
|
}
|
|
184
|
+
const pinoLogger = pino()
|
|
185
|
+
const pinoLoggerServer: FastifyInstance = fastify({ loggerInstance: pinoLogger })
|
|
186
|
+
|
|
187
|
+
expect(pinoLoggerServer).type.toBeAssignableTo<FastifyInstance>()
|
|
183
188
|
expect(fastify({ logger: customLogger })).type.toBeAssignableTo<
|
|
184
189
|
FastifyInstance<http.Server, http.IncomingMessage, http.ServerResponse, FastifyBaseLogger>
|
|
185
190
|
>()
|
|
@@ -356,5 +361,9 @@ fastify({ routerOptions: { allowUnsafeRegex: true } })
|
|
|
356
361
|
fastify({ routerOptions: { allowUnsafeRegex: false } })
|
|
357
362
|
expect(fastify).type.not.toBeCallableWith({ routerOptions: { allowUnsafeRegex: 'invalid' } })
|
|
358
363
|
|
|
364
|
+
fastify({ routerOptions: { compile: true } })
|
|
365
|
+
fastify({ routerOptions: { compile: false } })
|
|
366
|
+
expect(fastify).type.not.toBeCallableWith({ routerOptions: { compile: 'invalid' } })
|
|
367
|
+
|
|
359
368
|
expect(fastify({ allowErrorHandlerOverride: true })).type.toBeAssignableTo<FastifyInstance>()
|
|
360
369
|
expect(fastify({ allowErrorHandlerOverride: false })).type.toBeAssignableTo<FastifyInstance>()
|
|
@@ -29,7 +29,7 @@ expect(server.addSchema({ schemas: [] })).type.toBe<FastifyInstance>()
|
|
|
29
29
|
expect(server.pluginName).type.toBe<string>()
|
|
30
30
|
|
|
31
31
|
expect(server.getSchemas()).type.toBe<Record<string, unknown>>()
|
|
32
|
-
expect(server.addresses()).type.toBe<AddressInfo
|
|
32
|
+
expect(server.addresses()).type.toBe<Array<AddressInfo | string>>()
|
|
33
33
|
expect(server.getSchema('SchemaId')).type.toBe<unknown>()
|
|
34
34
|
expect(server.printRoutes()).type.toBe<string>()
|
|
35
35
|
expect(server.printPlugins()).type.toBe<string>()
|
package/test/types/route.tst.ts
CHANGED
|
@@ -58,6 +58,15 @@ const asyncPreHandler = async (request: FastifyRequest) => {
|
|
|
58
58
|
|
|
59
59
|
fastify().get('/', { preHandler: asyncPreHandler }, async () => 'this is an example')
|
|
60
60
|
|
|
61
|
+
fastify().route({
|
|
62
|
+
method: 'GET',
|
|
63
|
+
url: '/',
|
|
64
|
+
onRequest: async function () {
|
|
65
|
+
expect(this).type.toBe<FastifyInstance>()
|
|
66
|
+
},
|
|
67
|
+
handler: async () => 'ok'
|
|
68
|
+
})
|
|
69
|
+
|
|
61
70
|
fastify().get(
|
|
62
71
|
'/',
|
|
63
72
|
{ config: { foo: 'bar', bar: 100, includeMessage: true } },
|
|
@@ -74,6 +83,22 @@ fastify().get(
|
|
|
74
83
|
}
|
|
75
84
|
)
|
|
76
85
|
|
|
86
|
+
fastify().get(
|
|
87
|
+
'/',
|
|
88
|
+
{ logLevel: 'info', logSerializers: { test: (value: number) => 'X' + value } },
|
|
89
|
+
routeHandler
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
fastify().route({
|
|
93
|
+
method: 'GET',
|
|
94
|
+
url: '/',
|
|
95
|
+
logSerializers: {
|
|
96
|
+
// serializers may return objects as well as strings
|
|
97
|
+
req: (req: FastifyRequest) => ({ url: req.url })
|
|
98
|
+
},
|
|
99
|
+
handler: routeHandler
|
|
100
|
+
})
|
|
101
|
+
|
|
77
102
|
type LowerCaseHTTPMethods = 'delete' | 'get' | 'head' | 'patch' | 'post' | 'put' |
|
|
78
103
|
'options' | 'query' | 'propfind' | 'proppatch' | 'mkcol' | 'copy' | 'move' | 'lock' |
|
|
79
104
|
'unlock' | 'trace' | 'search' | 'mkcalendar' | 'report'
|
|
@@ -495,6 +520,12 @@ expect(fastify().hasRoute({
|
|
|
495
520
|
method: 'GET'
|
|
496
521
|
})).type.toBe<boolean>()
|
|
497
522
|
|
|
523
|
+
fastify().hasRoute({
|
|
524
|
+
url: '/',
|
|
525
|
+
// @ts-expect-error Type 'string[]' is not assignable to type 'HTTPMethods'.
|
|
526
|
+
method: ['GET', 'POST']
|
|
527
|
+
})
|
|
528
|
+
|
|
498
529
|
expect(fastify().hasRoute({
|
|
499
530
|
url: '/',
|
|
500
531
|
method: 'GET',
|
|
@@ -539,6 +570,12 @@ expect(
|
|
|
539
570
|
})
|
|
540
571
|
).type.toBe<Omit<FindMyWayFindResult<RawServerDefault>, 'store'>>()
|
|
541
572
|
|
|
573
|
+
fastify().findRoute({
|
|
574
|
+
url: '/',
|
|
575
|
+
// @ts-expect-error Type 'string[]' is not assignable to type 'HTTPMethods'.
|
|
576
|
+
method: ['GET', 'POST']
|
|
577
|
+
})
|
|
578
|
+
|
|
542
579
|
// we should not expose store
|
|
543
580
|
expect(fastify().findRoute({
|
|
544
581
|
url: '/',
|
package/test/types/using.tst.ts
CHANGED
|
@@ -12,3 +12,23 @@ test("has 'Symbol.dispose'", async () => {
|
|
|
12
12
|
expect(app).type.toBeAssignableTo<FastifyInstance>()
|
|
13
13
|
expect(app[Symbol.asyncDispose]).type.toBe<() => Promise<undefined>>()
|
|
14
14
|
})
|
|
15
|
+
|
|
16
|
+
test("addHook('onClose') accepts AsyncDisposable", () => {
|
|
17
|
+
const app = fastify()
|
|
18
|
+
|
|
19
|
+
const asyncDisposable: AsyncDisposable = {
|
|
20
|
+
async [Symbol.asyncDispose] () {}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
expect(app.addHook('onClose', asyncDisposable)).type.toBeAssignableTo<FastifyInstance>()
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test("addHook('onClose') accepts Disposable", () => {
|
|
27
|
+
const app = fastify()
|
|
28
|
+
|
|
29
|
+
const syncDisposable: Disposable = {
|
|
30
|
+
[Symbol.dispose] () {}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
expect(app.addHook('onClose', syncDisposable)).type.toBeAssignableTo<FastifyInstance>()
|
|
34
|
+
})
|
|
@@ -252,6 +252,26 @@ test('attached validationError exposes the same message sent by the default hand
|
|
|
252
252
|
t.assert.strictEqual(notAttached.statusCode, 400)
|
|
253
253
|
})
|
|
254
254
|
|
|
255
|
+
test('default validation errors are FST_ERR_VALIDATION errors without a stack trace', async (t) => {
|
|
256
|
+
t.plan(5)
|
|
257
|
+
|
|
258
|
+
const fastify = Fastify()
|
|
259
|
+
|
|
260
|
+
let validationError
|
|
261
|
+
fastify.post('/', { schema, attachValidation: true }, function (req, reply) {
|
|
262
|
+
validationError = req.validationError
|
|
263
|
+
reply.code(400).send()
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
await fastify.inject({ method: 'POST', payload: { hello: 'michelangelo' }, url: '/' })
|
|
267
|
+
|
|
268
|
+
t.assert.ok(validationError instanceof Fastify.errorCodes.FST_ERR_VALIDATION)
|
|
269
|
+
t.assert.ok(validationError instanceof Error)
|
|
270
|
+
t.assert.strictEqual(validationError.name, 'FastifyError')
|
|
271
|
+
t.assert.strictEqual(validationError.message, "body must have required property 'name'")
|
|
272
|
+
t.assert.strictEqual(validationError.stack, undefined)
|
|
273
|
+
})
|
|
274
|
+
|
|
255
275
|
test('should respect when attachValidation is explicitly set to false', async (t) => {
|
|
256
276
|
t.plan(2)
|
|
257
277
|
|
|
@@ -303,7 +323,7 @@ test('Attached validation error should take precedence over setErrorHandler', as
|
|
|
303
323
|
url: '/'
|
|
304
324
|
})
|
|
305
325
|
|
|
306
|
-
t.assert.deepStrictEqual(response.payload, "Attached:
|
|
326
|
+
t.assert.deepStrictEqual(response.payload, "Attached: FastifyError [FST_ERR_VALIDATION]: body must have required property 'name'")
|
|
307
327
|
t.assert.strictEqual(response.statusCode, 400)
|
|
308
328
|
})
|
|
309
329
|
|
package/types/errors.d.ts
CHANGED
|
@@ -83,7 +83,6 @@ export type FastifyErrorCodes = Record<
|
|
|
83
83
|
'FST_ERR_ROUTE_HANDLER_TIMEOUT_OPTION_NOT_INT' |
|
|
84
84
|
'FST_ERR_ROUTE_REWRITE_NOT_STR' |
|
|
85
85
|
'FST_ERR_ROUTE_MISSING_CONTENT_TYPE' |
|
|
86
|
-
'FST_ERR_ROUTE_MISSING_CONTENT' |
|
|
87
86
|
'FST_ERR_REOPENED_CLOSE_SERVER' |
|
|
88
87
|
'FST_ERR_REOPENED_SERVER' |
|
|
89
88
|
'FST_ERR_INSTANCE_ALREADY_STARTED' |
|
package/types/instance.d.ts
CHANGED
|
@@ -130,7 +130,7 @@ export interface FastifyInstance<
|
|
|
130
130
|
version: string;
|
|
131
131
|
log: Logger;
|
|
132
132
|
listeningOrigin: string;
|
|
133
|
-
addresses(): AddressInfo
|
|
133
|
+
addresses(): Array<AddressInfo | string>
|
|
134
134
|
withTypeProvider<Provider extends FastifyTypeProvider>(): FastifyInstance<RawServer, RawRequest, RawReply, Logger,
|
|
135
135
|
Provider>;
|
|
136
136
|
|
|
@@ -215,13 +215,13 @@ export interface FastifyInstance<
|
|
|
215
215
|
RouteGeneric extends RouteGenericInterface = RouteGenericInterface,
|
|
216
216
|
ContextConfig = ContextConfigDefault,
|
|
217
217
|
SchemaCompiler extends FastifySchema = FastifySchema
|
|
218
|
-
>(opts: Pick<RouteOptions<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider>, '
|
|
218
|
+
>(opts: Pick<RouteOptions<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider>, 'url' | 'constraints'> & { method: HTTPMethods }): boolean;
|
|
219
219
|
|
|
220
220
|
findRoute<
|
|
221
221
|
RouteGeneric extends RouteGenericInterface = RouteGenericInterface,
|
|
222
222
|
ContextConfig = ContextConfigDefault,
|
|
223
223
|
SchemaCompiler extends FastifySchema = FastifySchema
|
|
224
|
-
>(opts: Pick<RouteOptions<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider>, '
|
|
224
|
+
>(opts: Pick<RouteOptions<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider>, 'url' | 'constraints'> & { method: HTTPMethods }): Omit<FindMyWayFindResult<RawServer>, 'store'>;
|
|
225
225
|
|
|
226
226
|
// addHook: overloads
|
|
227
227
|
|
|
@@ -485,6 +485,10 @@ export interface FastifyInstance<
|
|
|
485
485
|
/**
|
|
486
486
|
* Triggered when fastify.close() is invoked to stop the server. It is useful when plugins need a "shutdown" event, for example to close an open connection to a database.
|
|
487
487
|
*/
|
|
488
|
+
addHook(
|
|
489
|
+
name: 'onClose',
|
|
490
|
+
hook: AsyncDisposable | Disposable,
|
|
491
|
+
): FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider>;
|
|
488
492
|
addHook<
|
|
489
493
|
Fn extends onCloseHookHandler | onCloseAsyncHookHandler = onCloseHookHandler
|
|
490
494
|
>(
|
|
@@ -579,7 +583,7 @@ export interface FastifyInstance<
|
|
|
579
583
|
* which allows for modifying or adding child logger bindings and logger options, or
|
|
580
584
|
* returning a completely custom child logger implementation.
|
|
581
585
|
*/
|
|
582
|
-
childLoggerFactory: FastifyChildLoggerFactory<RawServer, RawRequest, RawReply,
|
|
586
|
+
childLoggerFactory: FastifyChildLoggerFactory<RawServer, RawRequest, RawReply, FastifyBaseLogger, TypeProvider>;
|
|
583
587
|
|
|
584
588
|
/**
|
|
585
589
|
* Hook function that is called when creating a child logger instance for each request
|
|
@@ -598,7 +602,7 @@ export interface FastifyInstance<
|
|
|
598
602
|
* }
|
|
599
603
|
* ```
|
|
600
604
|
*/
|
|
601
|
-
setChildLoggerFactory(factory: FastifyChildLoggerFactory<RawServer, RawRequest, RawReply,
|
|
605
|
+
setChildLoggerFactory(factory: FastifyChildLoggerFactory<RawServer, RawRequest, RawReply, FastifyBaseLogger,
|
|
602
606
|
TypeProvider>): FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider>;
|
|
603
607
|
|
|
604
608
|
/**
|
package/types/route.d.ts
CHANGED
|
@@ -46,7 +46,8 @@ export interface RouteConstraint {
|
|
|
46
46
|
/**
|
|
47
47
|
* Route shorthand options for the various shorthand methods
|
|
48
48
|
*/
|
|
49
|
-
type RouteShorthandHook<T extends (...args: any) => any> =
|
|
49
|
+
type RouteShorthandHook<T extends (this: any, ...args: any) => any> =
|
|
50
|
+
(this: ThisParameterType<T>, ...args: Parameters<T>) => void | Promise<unknown>
|
|
50
51
|
|
|
51
52
|
export interface RouteShorthandOptions<
|
|
52
53
|
RawServer extends RawServerBase = RawServerDefault,
|
|
@@ -67,6 +68,7 @@ export interface RouteShorthandOptions<
|
|
|
67
68
|
bodyLimit?: number;
|
|
68
69
|
handlerTimeout?: number;
|
|
69
70
|
logLevel?: LogLevel;
|
|
71
|
+
logSerializers?: Record<string, (value: any) => any>;
|
|
70
72
|
config?: FastifyContextConfig & ContextConfig;
|
|
71
73
|
constraints?: RouteConstraint,
|
|
72
74
|
prefixTrailingSlash?: 'slash' | 'no-slash' | 'both';
|
|
@@ -78,7 +80,7 @@ export interface RouteShorthandOptions<
|
|
|
78
80
|
reply: FastifyReply<RouteGeneric, RawServer, RawRequest, RawReply, ContextConfig, NoInfer<SchemaCompiler>,
|
|
79
81
|
TypeProvider>
|
|
80
82
|
) => void;
|
|
81
|
-
childLoggerFactory?: FastifyChildLoggerFactory<RawServer, RawRequest, RawReply,
|
|
83
|
+
childLoggerFactory?: FastifyChildLoggerFactory<RawServer, RawRequest, RawReply, FastifyBaseLogger, TypeProvider>;
|
|
82
84
|
schemaErrorFormatter?: SchemaErrorFormatter;
|
|
83
85
|
|
|
84
86
|
// hooks
|