fastify 3.11.0 → 3.14.1

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 (76) hide show
  1. package/README.md +15 -10
  2. package/SECURITY.md +2 -2
  3. package/build/build-validation.js +25 -1
  4. package/docs/Benchmarking.md +3 -3
  5. package/docs/ContentTypeParser.md +21 -0
  6. package/docs/Decorators.md +1 -1
  7. package/docs/Ecosystem.md +38 -26
  8. package/docs/Encapsulation.md +4 -1
  9. package/docs/Errors.md +41 -41
  10. package/docs/Getting-Started.md +2 -2
  11. package/docs/HTTP2.md +1 -1
  12. package/docs/Hooks.md +35 -4
  13. package/docs/LTS.md +1 -1
  14. package/docs/Lifecycle.md +1 -1
  15. package/docs/Logging.md +4 -4
  16. package/docs/Middleware.md +3 -3
  17. package/docs/Migration-Guide-V3.md +3 -3
  18. package/docs/Plugins-Guide.md +15 -15
  19. package/docs/Plugins.md +7 -7
  20. package/docs/Recommendations.md +3 -4
  21. package/docs/Reply.md +4 -4
  22. package/docs/Request.md +1 -1
  23. package/docs/Routes.md +65 -10
  24. package/docs/Server.md +80 -14
  25. package/docs/Serverless.md +43 -64
  26. package/docs/Style-Guide.md +24 -19
  27. package/docs/Testing.md +5 -5
  28. package/docs/TypeScript.md +159 -17
  29. package/docs/Validation-and-Serialization.md +62 -6
  30. package/docs/Write-Plugin.md +3 -3
  31. package/fastify.d.ts +14 -3
  32. package/fastify.js +52 -18
  33. package/lib/configValidator.js +288 -53
  34. package/lib/contentTypeParser.js +28 -7
  35. package/lib/errors.js +1 -1
  36. package/lib/pluginOverride.js +5 -5
  37. package/lib/reply.js +35 -28
  38. package/lib/reqIdGenFactory.js +2 -1
  39. package/lib/request.js +1 -1
  40. package/lib/route.js +20 -27
  41. package/lib/schema-compilers.js +5 -3
  42. package/lib/schema-controller.js +106 -0
  43. package/lib/schemas.js +13 -23
  44. package/lib/symbols.js +1 -3
  45. package/lib/warnings.js +4 -0
  46. package/package.json +22 -17
  47. package/test/constrained-routes.test.js +184 -0
  48. package/test/content-parser.test.js +179 -7
  49. package/test/context-config.test.js +52 -0
  50. package/test/custom-parser.test.js +262 -2
  51. package/test/hooks-async.test.js +46 -0
  52. package/test/hooks.test.js +47 -0
  53. package/test/internals/initialConfig.test.js +30 -5
  54. package/test/internals/reply.test.js +2 -2
  55. package/test/internals/request.test.js +3 -9
  56. package/test/pretty-print.test.js +28 -0
  57. package/test/route.test.js +0 -2
  58. package/test/schema-feature.test.js +134 -4
  59. package/test/schema-serialization.test.js +42 -0
  60. package/test/schema-special-usage.test.js +234 -0
  61. package/test/schema-validation.test.js +1 -1
  62. package/test/stream.test.js +90 -0
  63. package/test/throw.test.js +1 -1
  64. package/test/types/content-type-parser.test-d.ts +8 -2
  65. package/test/types/fastify.test-d.ts +27 -0
  66. package/test/types/instance.test-d.ts +43 -1
  67. package/test/types/logger.test-d.ts +8 -3
  68. package/test/types/reply.test-d.ts +2 -1
  69. package/test/types/schema.test-d.ts +52 -1
  70. package/test/versioned-routes.test.js +99 -18
  71. package/types/content-type-parser.d.ts +10 -4
  72. package/types/instance.d.ts +57 -7
  73. package/types/logger.d.ts +1 -1
  74. package/types/reply.d.ts +2 -1
  75. package/types/route.d.ts +15 -11
  76. package/types/schema.d.ts +5 -4
@@ -3,7 +3,7 @@
3
3
  const { test } = require('tap')
4
4
  const Fastify = require('..')
5
5
  const fp = require('fastify-plugin')
6
- const { kSchemas } = require('../lib/symbols.js')
6
+ const { kSchemaController } = require('../lib/symbols.js')
7
7
 
8
8
  const echoParams = (req, reply) => { reply.send(req.params) }
9
9
  const echoBody = (req, reply) => { reply.send(req.body) }
@@ -38,7 +38,7 @@ test('The schemas should be added to an internal storage', t => {
38
38
  const fastify = Fastify()
39
39
  const schema = { $id: 'id', my: 'schema' }
40
40
  fastify.addSchema(schema)
41
- t.deepEqual(fastify[kSchemas].store, { id: schema })
41
+ t.deepEqual(fastify[kSchemaController].schemaBucket.store, { id: schema })
42
42
  })
43
43
 
44
44
  test('The schemas should be accessible via getSchemas', t => {
@@ -121,8 +121,8 @@ test('Get compilers is empty when settle on routes', t => {
121
121
  url: '/'
122
122
  }, (err, res) => {
123
123
  t.error(err)
124
- t.equal(fastify.validatorCompiler, null)
125
- t.equal(fastify.serializerCompiler, null)
124
+ t.equal(fastify.validatorCompiler, undefined)
125
+ t.equal(fastify.serializerCompiler, undefined)
126
126
  })
127
127
  })
128
128
 
@@ -1159,3 +1159,133 @@ test('The schema compiler recreate itself if needed', t => {
1159
1159
 
1160
1160
  fastify.ready(err => { t.error(err) })
1161
1161
  })
1162
+
1163
+ test('Schema controller setter', t => {
1164
+ t.plan(2)
1165
+ Fastify({ schemaController: {} })
1166
+ t.pass('allow empty object')
1167
+
1168
+ try {
1169
+ Fastify({ schemaController: { bucket: {} } })
1170
+ t.fail('the bucket option must be a function')
1171
+ } catch (err) {
1172
+ t.is(err.message, "schemaController.bucket option should be a function, instead got 'object'")
1173
+ }
1174
+ })
1175
+
1176
+ test('Schema controller bucket', t => {
1177
+ t.plan(10)
1178
+
1179
+ let added = 0
1180
+ let builtBucket = 0
1181
+
1182
+ const initStoreQueue = []
1183
+
1184
+ function factoryBucket (storeInit) {
1185
+ builtBucket++
1186
+ t.deepEqual(initStoreQueue.pop(), storeInit)
1187
+ const store = new Map(storeInit)
1188
+ return {
1189
+ add (schema) {
1190
+ added++
1191
+ store.set(schema.$id, schema)
1192
+ },
1193
+ getSchema (id) {
1194
+ return store.get(id)
1195
+ },
1196
+ getSchemas () {
1197
+ // what is returned by this function, will be the `storeInit` parameter
1198
+ initStoreQueue.push(store)
1199
+ return store
1200
+ }
1201
+ }
1202
+ }
1203
+
1204
+ const fastify = Fastify({
1205
+ schemaController: {
1206
+ bucket: factoryBucket
1207
+ }
1208
+ })
1209
+
1210
+ fastify.register(async (instance) => {
1211
+ instance.addSchema({ $id: 'b', type: 'string' })
1212
+ instance.addHook('onReady', function (done) {
1213
+ t.equals(instance.getSchemas().size, 2)
1214
+ done()
1215
+ })
1216
+ instance.register(async (subinstance) => {
1217
+ subinstance.addSchema({ $id: 'c', type: 'string' })
1218
+ subinstance.addHook('onReady', function (done) {
1219
+ t.equals(subinstance.getSchemas().size, 3)
1220
+ done()
1221
+ })
1222
+ })
1223
+ })
1224
+
1225
+ fastify.register(async (instance) => {
1226
+ instance.addHook('onReady', function (done) {
1227
+ t.equals(instance.getSchemas().size, 1)
1228
+ done()
1229
+ })
1230
+ })
1231
+
1232
+ fastify.addSchema({ $id: 'a', type: 'string' })
1233
+
1234
+ fastify.ready(err => {
1235
+ t.error(err)
1236
+ t.equals(added, 3, 'three schema added')
1237
+ t.equals(builtBucket, 4, 'one bucket built for every register call + 1 for the root instance')
1238
+ })
1239
+ })
1240
+
1241
+ test('setSchemaController per instance', t => {
1242
+ t.plan(7)
1243
+ const fastify = Fastify({})
1244
+
1245
+ fastify.register(async (instance1) => {
1246
+ instance1.setSchemaController({
1247
+ bucket: function factoryBucket (storeInit) {
1248
+ t.pass('instance1 has created the bucket')
1249
+ return {
1250
+ add (schema) { t.fail('add is not called') },
1251
+ getSchema (id) { t.fail('getSchema is not called') },
1252
+ getSchemas () { t.fail('getSchemas is not called') }
1253
+ }
1254
+ }
1255
+ })
1256
+ })
1257
+
1258
+ fastify.register(async (instance2) => {
1259
+ const bSchema = { $id: 'b', type: 'string' }
1260
+
1261
+ instance2.setSchemaController({
1262
+ bucket: function factoryBucket (storeInit) {
1263
+ t.pass('instance2 has created the bucket')
1264
+ const map = {}
1265
+ return {
1266
+ add (schema) {
1267
+ t.equals(schema.$id, bSchema.$id, 'add is called')
1268
+ map[schema.$id] = schema
1269
+ },
1270
+ getSchema (id) {
1271
+ t.pass('getSchema is called')
1272
+ return map[id]
1273
+ },
1274
+ getSchemas () {
1275
+ t.pass('getSchemas is called')
1276
+ }
1277
+ }
1278
+ }
1279
+ })
1280
+
1281
+ instance2.addSchema(bSchema)
1282
+
1283
+ instance2.addHook('onReady', function (done) {
1284
+ instance2.getSchemas()
1285
+ t.deepEquals(instance2.getSchema('b'), bSchema, 'the schema are loaded')
1286
+ done()
1287
+ })
1288
+ })
1289
+
1290
+ fastify.ready(err => { t.error(err) })
1291
+ })
@@ -498,3 +498,45 @@ test('The schema changes the default error handler output', async t => {
498
498
  t.equals(res.statusCode, 500)
499
499
  t.deepEquals(res.json(), { error: 'Internal Server Error', message: '500 message', customId: 42 })
500
500
  })
501
+
502
+ test('do not crash if status code serializer errors', async t => {
503
+ const fastify = Fastify()
504
+
505
+ const requiresFoo = {
506
+ properties: { foo: { type: 'string' } },
507
+ required: ['foo']
508
+ }
509
+
510
+ const someUserErrorType2 = {
511
+ properties: {
512
+ code: { type: 'number' }
513
+ },
514
+ required: ['code']
515
+ }
516
+
517
+ fastify.get(
518
+ '/',
519
+ {
520
+ schema: {
521
+ query: requiresFoo,
522
+ response: { 400: someUserErrorType2 }
523
+ }
524
+ },
525
+ (request, reply) => {
526
+ t.fail('handler, should not be called')
527
+ }
528
+ )
529
+
530
+ const res = await fastify.inject({
531
+ path: '/',
532
+ query: {
533
+ notfoo: true
534
+ }
535
+ })
536
+ t.equals(res.statusCode, 500)
537
+ t.deepEquals(res.json(), {
538
+ statusCode: 500,
539
+ error: 'Internal Server Error',
540
+ message: '"code" is required!'
541
+ })
542
+ })
@@ -1,6 +1,8 @@
1
1
  'use strict'
2
2
 
3
3
  const { test } = require('tap')
4
+ const AJV = require('ajv')
5
+ const S = require('fluent-json-schema')
4
6
  const Fastify = require('..')
5
7
  const ajvMergePatch = require('ajv-merge-patch')
6
8
 
@@ -221,3 +223,235 @@ test('Should handle $patch keywords in body', t => {
221
223
  })
222
224
  })
223
225
  })
226
+
227
+ test("serializer read validator's schemas", t => {
228
+ t.plan(4)
229
+ const ajvInstance = new AJV()
230
+
231
+ const baseSchema = {
232
+ $id: 'http://example.com/schemas/base',
233
+ definitions: {
234
+ hello: { type: 'string' }
235
+ },
236
+ type: 'object',
237
+ properties: {
238
+ hello: { $ref: '#/definitions/hello' }
239
+ }
240
+ }
241
+
242
+ const refSchema = {
243
+ $id: 'http://example.com/schemas/ref',
244
+ type: 'object',
245
+ properties: {
246
+ hello: { $ref: 'http://example.com/schemas/base#/definitions/hello' }
247
+ }
248
+ }
249
+
250
+ ajvInstance.addSchema(baseSchema)
251
+ ajvInstance.addSchema(refSchema)
252
+
253
+ const fastify = Fastify({
254
+ schemaController: {
255
+ bucket: function factory (storeInit) {
256
+ t.notOk(storeInit, 'is is always empty because fastify.addSchema is not called')
257
+ return {
258
+ getSchemas () {
259
+ return {
260
+ [baseSchema.$id]: ajvInstance.getSchema(baseSchema.$id).schema,
261
+ [refSchema.$id]: ajvInstance.getSchema(refSchema.$id).schema
262
+ }
263
+ }
264
+ }
265
+ }
266
+ }
267
+ })
268
+
269
+ fastify.setValidatorCompiler(function ({ schema }) {
270
+ return ajvInstance.compile(schema)
271
+ })
272
+
273
+ fastify.get('/', {
274
+ schema: {
275
+ response: {
276
+ '2xx': ajvInstance.getSchema('http://example.com/schemas/ref').schema
277
+ }
278
+ },
279
+ handler (req, res) { res.send({ hello: 'world', evict: 'this' }) }
280
+ })
281
+
282
+ fastify.inject('/', (err, res) => {
283
+ t.error(err)
284
+ t.equals(res.statusCode, 200)
285
+ t.deepEquals(res.json(), { hello: 'world' })
286
+ })
287
+ })
288
+
289
+ test('setSchemaController in a plugin', t => {
290
+ t.plan(5)
291
+ const baseSchema = {
292
+ $id: 'urn:schema:base',
293
+ definitions: {
294
+ hello: { type: 'string' }
295
+ },
296
+ type: 'object',
297
+ properties: {
298
+ hello: { $ref: '#/definitions/hello' }
299
+ }
300
+ }
301
+
302
+ const refSchema = {
303
+ $id: 'urn:schema:ref',
304
+ type: 'object',
305
+ properties: {
306
+ hello: { $ref: 'urn:schema:base#/definitions/hello' }
307
+ }
308
+ }
309
+
310
+ const ajvInstance = new AJV()
311
+ ajvInstance.addSchema(baseSchema)
312
+ ajvInstance.addSchema(refSchema)
313
+
314
+ const fastify = Fastify()
315
+ fastify.register(schemaPlugin)
316
+ fastify.get('/', {
317
+ schema: {
318
+ query: ajvInstance.getSchema('urn:schema:ref').schema,
319
+ response: {
320
+ '2xx': ajvInstance.getSchema('urn:schema:ref').schema
321
+ }
322
+ },
323
+ handler (req, res) {
324
+ res.send({ hello: 'world', evict: 'this' })
325
+ }
326
+ })
327
+
328
+ fastify.inject('/', (err, res) => {
329
+ t.error(err)
330
+ t.equals(res.statusCode, 200)
331
+ t.deepEquals(res.json(), { hello: 'world' })
332
+ })
333
+
334
+ async function schemaPlugin (server) {
335
+ server.setSchemaController({
336
+ bucket () {
337
+ t.pass('the bucket is created')
338
+ return {
339
+ addSchema (source) {
340
+ ajvInstance.addSchema(source)
341
+ },
342
+ getSchema (id) {
343
+ return ajvInstance.getSchema(id).schema
344
+ },
345
+ getSchemas () {
346
+ return {
347
+ 'urn:schema:base': baseSchema,
348
+ 'urn:schema:ref': refSchema
349
+ }
350
+ }
351
+ }
352
+ }
353
+ })
354
+ server.setValidatorCompiler(function ({ schema }) {
355
+ t.pass('the querystring schema is compiled')
356
+ return ajvInstance.compile(schema)
357
+ })
358
+ }
359
+ schemaPlugin[Symbol.for('skip-override')] = true
360
+ })
361
+
362
+ test('side effect on schema let the server crash', async t => {
363
+ const firstSchema = {
364
+ $id: 'example1',
365
+ type: 'object',
366
+ properties: {
367
+ name: {
368
+ type: 'string'
369
+ }
370
+ }
371
+ }
372
+
373
+ const reusedSchema = {
374
+ $id: 'example2',
375
+ type: 'object',
376
+ properties: {
377
+ name: {
378
+ oneOf: [
379
+ {
380
+ $ref: 'example1'
381
+ }
382
+ ]
383
+ }
384
+ }
385
+ }
386
+
387
+ const fastify = Fastify()
388
+ fastify.addSchema(firstSchema)
389
+
390
+ fastify.post('/a', {
391
+ handler: async () => 'OK',
392
+ schema: {
393
+ body: reusedSchema,
394
+ response: { 200: reusedSchema }
395
+ }
396
+ })
397
+ fastify.post('/b', {
398
+ handler: async () => 'OK',
399
+ schema: {
400
+ body: reusedSchema,
401
+ response: { 200: reusedSchema }
402
+ }
403
+ })
404
+
405
+ await fastify.ready()
406
+ })
407
+
408
+ test('only response schema trigger AJV pollution', async t => {
409
+ const ShowSchema = S.object().id('ShowSchema').prop('name', S.string())
410
+ const ListSchema = S.array().id('ListSchema').items(S.ref('ShowSchema#'))
411
+
412
+ const fastify = Fastify()
413
+ fastify.addSchema(ListSchema)
414
+ fastify.addSchema(ShowSchema)
415
+
416
+ const routeResponseSchemas = {
417
+ schema: { response: { 200: S.ref('ListSchema#') } }
418
+ }
419
+
420
+ fastify.register(
421
+ async (app) => { app.get('/resource/', routeResponseSchemas, () => ({})) },
422
+ { prefix: '/prefix1' }
423
+ )
424
+ fastify.register(
425
+ async (app) => { app.get('/resource/', routeResponseSchemas, () => ({})) },
426
+ { prefix: '/prefix2' }
427
+ )
428
+
429
+ await fastify.ready()
430
+ })
431
+
432
+ test('only response schema trigger AJV pollution #2', async t => {
433
+ const ShowSchema = S.object().id('ShowSchema').prop('name', S.string())
434
+ const ListSchema = S.array().id('ListSchema').items(S.ref('ShowSchema#'))
435
+
436
+ const fastify = Fastify()
437
+ fastify.addSchema(ListSchema)
438
+ fastify.addSchema(ShowSchema)
439
+
440
+ const routeResponseSchemas = {
441
+ schema: {
442
+ params: S.ref('ListSchema#'),
443
+ response: { 200: S.ref('ListSchema#') }
444
+ }
445
+ }
446
+
447
+ fastify.register(
448
+ async (app) => { app.get('/resource/', routeResponseSchemas, () => ({})) },
449
+ { prefix: '/prefix1' }
450
+ )
451
+ fastify.register(
452
+ async (app) => { app.get('/resource/', routeResponseSchemas, () => ({})) },
453
+ { prefix: '/prefix2' }
454
+ )
455
+
456
+ await fastify.ready()
457
+ })
@@ -178,7 +178,7 @@ test('Encapsulation', t => {
178
178
 
179
179
  fastify.register((instance, opts, done) => {
180
180
  instance.post('/clean', function (req, reply) {
181
- t.equals(instance.validatorCompiler, null)
181
+ t.equals(instance.validatorCompiler, undefined)
182
182
  reply.send({ foo: 'bar' })
183
183
  })
184
184
  done()
@@ -263,6 +263,68 @@ test('Destroying streams prematurely should call close method', t => {
263
263
  })
264
264
  })
265
265
 
266
+ test('Destroying streams prematurely should call close method when destroy is not a function', t => {
267
+ t.plan(7)
268
+
269
+ let fastify = null
270
+ const logStream = split(JSON.parse)
271
+ try {
272
+ fastify = Fastify({
273
+ logger: {
274
+ stream: logStream,
275
+ level: 'info'
276
+ }
277
+ })
278
+ } catch (e) {
279
+ t.fail()
280
+ }
281
+ const stream = require('stream')
282
+ const http = require('http')
283
+
284
+ // Test that "premature close" errors are logged with level warn
285
+ logStream.on('data', line => {
286
+ if (line.res) {
287
+ t.equal(line.msg, 'stream closed prematurely')
288
+ t.equal(line.level, 30)
289
+ }
290
+ })
291
+
292
+ fastify.get('/', function (request, reply) {
293
+ t.pass('Received request')
294
+
295
+ let sent = false
296
+ const reallyLongStream = new stream.Readable({
297
+ read: function () {
298
+ if (!sent) {
299
+ this.push(Buffer.from('hello\n'))
300
+ }
301
+ sent = true
302
+ }
303
+ })
304
+ reallyLongStream.destroy = true
305
+ reallyLongStream.close = () => t.ok('called')
306
+ reply.send(reallyLongStream)
307
+ })
308
+
309
+ fastify.listen(0, err => {
310
+ t.error(err)
311
+ fastify.server.unref()
312
+
313
+ const port = fastify.server.address().port
314
+
315
+ http.get(`http://localhost:${port}`, function (response) {
316
+ t.strictEqual(response.statusCode, 200)
317
+ response.on('readable', function () {
318
+ response.destroy()
319
+ })
320
+ // Node bug? Node never emits 'close' here.
321
+ response.on('aborted', function () {
322
+ t.pass('Response closed')
323
+ })
324
+ })
325
+ })
326
+ })
327
+
266
328
  test('Destroying streams prematurely should call abort method', t => {
267
329
  t.plan(7)
268
330
 
@@ -418,3 +480,31 @@ test('should support send module 200 and 404', t => {
418
480
  })
419
481
  })
420
482
  })
483
+
484
+ test('should destroy stream when response is ended', t => {
485
+ t.plan(4)
486
+ const stream = require('stream')
487
+ const fastify = Fastify()
488
+
489
+ fastify.get('/error', function (req, reply) {
490
+ const reallyLongStream = new stream.Readable({
491
+ read: function () {},
492
+ destroy: function (err, callback) {
493
+ t.ok('called')
494
+ callback(err)
495
+ }
496
+ })
497
+ reply.code(200).send(reallyLongStream)
498
+ reply.raw.end(Buffer.from('hello\n'))
499
+ })
500
+
501
+ fastify.listen(0, err => {
502
+ t.error(err)
503
+ fastify.server.unref()
504
+
505
+ sget(`http://localhost:${fastify.server.address().port}/error`, function (err, response) {
506
+ t.error(err)
507
+ t.strictEqual(response.statusCode, 200)
508
+ })
509
+ })
510
+ })
@@ -21,7 +21,7 @@ test('Fastify should throw on multiple assignment to the same route', t => {
21
21
  fastify.get('/', () => {})
22
22
 
23
23
  fastify.ready(err => {
24
- t.is(err.message, "Method 'GET' already declared for route '/'")
24
+ t.is(err.message, "Method 'GET' already declared for route '/' with constraints '{}'")
25
25
  })
26
26
  })
27
27
 
@@ -1,5 +1,5 @@
1
- import fastify from '../../fastify'
2
- import { expectType } from 'tsd'
1
+ import fastify, { FastifyContentTypeParser } from '../../fastify'
2
+ import { expectError, expectType } from 'tsd'
3
3
  import { IncomingMessage } from 'http'
4
4
  import { FastifyRequest } from '../../types/request'
5
5
 
@@ -56,3 +56,9 @@ expectType<void>(fastify().addContentTypeParser<Buffer>('bodyContentType', { par
56
56
  expectType<Buffer>(body)
57
57
  return null
58
58
  }))
59
+
60
+ expectType<FastifyContentTypeParser>(fastify().getDefaultJsonParser('error', 'ignore'))
61
+
62
+ expectError(fastify().getDefaultJsonParser('error', 'skip'))
63
+
64
+ expectError(fastify().getDefaultJsonParser('nothing', 'ignore'))
@@ -98,6 +98,33 @@ expectAssignable<FastifyInstance>(fastify({
98
98
  deriveVersion: () => 'foo'
99
99
  }
100
100
  }))
101
+ expectAssignable<FastifyInstance>(fastify({ constraints: {} }))
102
+ expectAssignable<FastifyInstance>(fastify({
103
+ constraints: {
104
+ version: {
105
+ name: 'version',
106
+ storage: () => ({
107
+ get: () => () => {},
108
+ set: () => { },
109
+ del: () => { },
110
+ empty: () => { }
111
+ }),
112
+ validate () {},
113
+ deriveConstraint: () => 'foo'
114
+ },
115
+ host: {
116
+ name: 'host',
117
+ storage: () => ({
118
+ get: () => () => {},
119
+ set: () => { },
120
+ del: () => { },
121
+ empty: () => { }
122
+ }),
123
+ validate () {},
124
+ deriveConstraint: () => 'foo'
125
+ }
126
+ }
127
+ }))
101
128
  expectAssignable<FastifyInstance>(fastify({ return503OnClosing: true }))
102
129
  expectAssignable<FastifyInstance>(fastify({
103
130
  ajv: {
@@ -1,5 +1,8 @@
1
- import fastify, { FastifyError, FastifyInstance, ValidationResult } from '../../fastify'
1
+ import fastify, { FastifyContentTypeParser, FastifyError, FastifyInstance, ValidationResult } from '../../fastify'
2
2
  import { expectAssignable, expectError, expectType } from 'tsd'
3
+ import { FastifyRequest } from '../../types/request'
4
+ import { FastifyReply } from '../../types/reply'
5
+ import { HookHandlerDoneFunction } from '../../types/hooks'
3
6
 
4
7
  const server = fastify()
5
8
 
@@ -15,6 +18,8 @@ expectAssignable<FastifyInstance>(server.addSchema({
15
18
 
16
19
  expectType<Record<string, unknown>>(server.getSchemas())
17
20
  expectType<unknown>(server.getSchema('SchemaId'))
21
+ expectType<string>(server.printRoutes())
22
+ expectType<string>(server.printPlugins())
18
23
 
19
24
  expectAssignable<FastifyInstance>(
20
25
  server.setErrorHandler(function (error, request, reply) {
@@ -36,6 +41,19 @@ server.setErrorHandler(fastifyErrorHandler)
36
41
  function nodeJSErrorHandler (error: NodeJS.ErrnoException) {}
37
42
  server.setErrorHandler(nodeJSErrorHandler)
38
43
 
44
+ function notFoundHandler (request: FastifyRequest, reply: FastifyReply) {}
45
+ function notFoundpreHandlerHandler (request: FastifyRequest, reply: FastifyReply, done: HookHandlerDoneFunction) { done() }
46
+ async function notFoundpreHandlerAsyncHandler (request: FastifyRequest, reply: FastifyReply) {}
47
+ function notFoundpreValidationHandler (request: FastifyRequest, reply: FastifyReply, done: HookHandlerDoneFunction) { done() }
48
+ async function notFoundpreValidationAsyncHandler (request: FastifyRequest, reply: FastifyReply) {}
49
+
50
+ server.setNotFoundHandler(notFoundHandler)
51
+ server.setNotFoundHandler({ preHandler: notFoundpreHandlerHandler }, notFoundHandler)
52
+ server.setNotFoundHandler({ preHandler: notFoundpreHandlerAsyncHandler }, notFoundHandler)
53
+ server.setNotFoundHandler({ preValidation: notFoundpreValidationHandler }, notFoundHandler)
54
+ server.setNotFoundHandler({ preValidation: notFoundpreValidationAsyncHandler }, notFoundHandler)
55
+ server.setNotFoundHandler({ preHandler: notFoundpreHandlerHandler, preValidation: notFoundpreValidationHandler }, notFoundHandler)
56
+
39
57
  function invalidErrorHandler (error: number) {}
40
58
  expectError(server.setErrorHandler(invalidErrorHandler))
41
59
 
@@ -84,3 +102,27 @@ expectType<FastifyInstance>(fastify().get('/', {
84
102
  expectAssignable<void>(server.errorHandler(error, request, reply))
85
103
  }
86
104
  }))
105
+
106
+ type InitialConfig = Readonly<{
107
+ connectionTimeout?: number,
108
+ keepAliveTimeout?: number,
109
+ bodyLimit?: number,
110
+ caseSensitive?: boolean,
111
+ http2?: boolean,
112
+ https?: boolean | Readonly<{ allowHTTP1: boolean }>,
113
+ ignoreTrailingSlash?: boolean,
114
+ disableRequestLogging?: boolean,
115
+ maxParamLength?: number,
116
+ onProtoPoisoning?: 'error' | 'remove' | 'ignore',
117
+ onConstructorPoisoning?: 'error' | 'remove' | 'ignore',
118
+ pluginTimeout?: number,
119
+ requestIdHeader?: string,
120
+ requestIdLogLabel?: string,
121
+ http2SessionTimeout?: number
122
+ }>
123
+
124
+ expectType<InitialConfig>(fastify().initialConfig)
125
+
126
+ expectType<FastifyContentTypeParser>(server.defaultTextParser)
127
+
128
+ expectType<FastifyContentTypeParser>(server.getDefaultJsonParser('ignore', 'error'))