fastify 4.23.2 → 4.24.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 (91) hide show
  1. package/README.md +1 -1
  2. package/docs/Guides/Ecosystem.md +6 -0
  3. package/docs/Reference/Hooks.md +1 -0
  4. package/docs/Reference/Plugins.md +1 -1
  5. package/docs/Reference/Reply.md +4 -3
  6. package/docs/Reference/Request.md +3 -2
  7. package/docs/Reference/Server.md +31 -3
  8. package/docs/Reference/Type-Providers.md +2 -2
  9. package/docs/Reference/TypeScript.md +21 -7
  10. package/fastify.d.ts +2 -2
  11. package/fastify.js +8 -1
  12. package/lib/contentTypeParser.js +1 -1
  13. package/lib/reply.js +20 -3
  14. package/lib/reqIdGenFactory.js +15 -9
  15. package/lib/request.js +1 -1
  16. package/lib/route.js +28 -7
  17. package/lib/schemas.js +3 -3
  18. package/lib/warnings.js +3 -1
  19. package/package.json +33 -33
  20. package/test/404s.test.js +31 -39
  21. package/test/async-await.test.js +1 -1
  22. package/test/async-dispose.test.js +21 -0
  23. package/test/build-certificate.js +90 -1
  24. package/test/close-pipelining.test.js +5 -5
  25. package/test/close.test.js +1 -5
  26. package/test/constrained-routes.test.js +127 -3
  27. package/test/custom-http-server.test.js +94 -91
  28. package/test/custom-parser.0.test.js +21 -47
  29. package/test/custom-parser.1.test.js +10 -732
  30. package/test/custom-parser.2.test.js +102 -0
  31. package/test/custom-parser.3.test.js +245 -0
  32. package/test/custom-parser.4.test.js +239 -0
  33. package/test/custom-parser.5.test.js +149 -0
  34. package/test/head.test.js +204 -0
  35. package/test/helper.js +30 -8
  36. package/test/hooks-async.test.js +163 -13
  37. package/test/hooks.on-listen.test.js +7 -6
  38. package/test/hooks.test.js +4 -15
  39. package/test/http2/closing.test.js +7 -15
  40. package/test/https/custom-https-server.test.js +43 -40
  41. package/test/input-validation.js +3 -3
  42. package/test/internals/reply.test.js +33 -4
  43. package/test/listen.1.test.js +101 -0
  44. package/test/listen.2.test.js +103 -0
  45. package/test/listen.3.test.js +87 -0
  46. package/test/listen.4.test.js +164 -0
  47. package/test/listen.deprecated.test.js +3 -9
  48. package/test/logger/instantiation.test.js +347 -0
  49. package/test/logger/logger-test-utils.js +47 -0
  50. package/test/logger/logging.test.js +406 -0
  51. package/test/logger/options.test.js +500 -0
  52. package/test/logger/request.test.js +292 -0
  53. package/test/logger/response.test.js +184 -0
  54. package/test/plugin.1.test.js +249 -0
  55. package/test/plugin.2.test.js +328 -0
  56. package/test/plugin.3.test.js +311 -0
  57. package/test/plugin.4.test.js +416 -0
  58. package/test/reply-code.test.js +64 -0
  59. package/test/reply-trailers.test.js +1 -2
  60. package/test/route.1.test.js +309 -0
  61. package/test/route.2.test.js +99 -0
  62. package/test/route.3.test.js +205 -0
  63. package/test/route.4.test.js +131 -0
  64. package/test/route.5.test.js +230 -0
  65. package/test/route.6.test.js +306 -0
  66. package/test/route.7.test.js +370 -0
  67. package/test/route.8.test.js +142 -0
  68. package/test/stream.1.test.js +108 -0
  69. package/test/stream.2.test.js +119 -0
  70. package/test/stream.3.test.js +192 -0
  71. package/test/stream.4.test.js +223 -0
  72. package/test/stream.5.test.js +194 -0
  73. package/test/trust-proxy.test.js +2 -4
  74. package/test/types/reply.test-d.ts +3 -3
  75. package/test/types/request.test-d.ts +9 -9
  76. package/test/types/type-provider.test-d.ts +89 -0
  77. package/test/types/using.test-d.ts +14 -0
  78. package/test/upgrade.test.js +3 -3
  79. package/types/context.d.ts +9 -2
  80. package/types/instance.d.ts +4 -1
  81. package/types/plugin.d.ts +2 -1
  82. package/types/reply.d.ts +2 -2
  83. package/types/request.d.ts +3 -3
  84. package/types/route.d.ts +5 -5
  85. package/test/listen.test.js +0 -427
  86. package/test/plugin.test.js +0 -1275
  87. package/test/route.test.js +0 -1762
  88. package/test/serial/logger.0.test.js +0 -866
  89. package/test/serial/logger.1.test.js +0 -862
  90. package/test/stream.test.js +0 -816
  91. /package/test/{serial → logger}/tap-parallel-not-ok +0 -0
@@ -0,0 +1,249 @@
1
+ 'use strict'
2
+
3
+ /* eslint no-prototype-builtins: 0 */
4
+
5
+ const t = require('tap')
6
+ const test = t.test
7
+ const Fastify = require('../fastify')
8
+ const sget = require('simple-get').concat
9
+ const fp = require('fastify-plugin')
10
+
11
+ test('require a plugin', t => {
12
+ t.plan(1)
13
+ const fastify = Fastify()
14
+ fastify.register(require('./plugin.helper'))
15
+ fastify.ready(() => {
16
+ t.ok(fastify.test)
17
+ })
18
+ })
19
+
20
+ test('plugin metadata - ignore prefix', t => {
21
+ t.plan(2)
22
+ const fastify = Fastify()
23
+
24
+ plugin[Symbol.for('skip-override')] = true
25
+ fastify.register(plugin, { prefix: 'foo' })
26
+
27
+ fastify.inject({
28
+ method: 'GET',
29
+ url: '/'
30
+ }, function (err, res) {
31
+ t.error(err)
32
+ t.equal(res.payload, 'hello')
33
+ })
34
+
35
+ function plugin (instance, opts, done) {
36
+ instance.get('/', function (request, reply) {
37
+ reply.send('hello')
38
+ })
39
+ done()
40
+ }
41
+ })
42
+
43
+ test('plugin metadata - naming plugins', async t => {
44
+ t.plan(2)
45
+ const fastify = Fastify()
46
+
47
+ fastify.register(require('./plugin.name.display'))
48
+ fastify.register(function (fastify, opts, done) {
49
+ // one line
50
+ t.equal(fastify.pluginName, 'function (fastify, opts, done) { -- // one line')
51
+ done()
52
+ })
53
+ fastify.register(function fooBar (fastify, opts, done) {
54
+ t.equal(fastify.pluginName, 'fooBar')
55
+ done()
56
+ })
57
+
58
+ await fastify.ready()
59
+ })
60
+
61
+ test('fastify.register with fastify-plugin should not encapsulate his code', t => {
62
+ t.plan(10)
63
+ const fastify = Fastify()
64
+
65
+ fastify.register((instance, opts, done) => {
66
+ instance.register(fp((i, o, n) => {
67
+ i.decorate('test', () => {})
68
+ t.ok(i.test)
69
+ n()
70
+ }))
71
+
72
+ t.notOk(instance.test)
73
+
74
+ // the decoration is added at the end
75
+ instance.after(() => {
76
+ t.ok(instance.test)
77
+ })
78
+
79
+ instance.get('/', (req, reply) => {
80
+ t.ok(instance.test)
81
+ reply.send({ hello: 'world' })
82
+ })
83
+
84
+ done()
85
+ })
86
+
87
+ fastify.ready(() => {
88
+ t.notOk(fastify.test)
89
+ })
90
+
91
+ fastify.listen({ port: 0 }, err => {
92
+ t.error(err)
93
+ t.teardown(() => { fastify.close() })
94
+
95
+ sget({
96
+ method: 'GET',
97
+ url: 'http://localhost:' + fastify.server.address().port
98
+ }, (err, response, body) => {
99
+ t.error(err)
100
+ t.equal(response.statusCode, 200)
101
+ t.equal(response.headers['content-length'], '' + body.length)
102
+ t.same(JSON.parse(body), { hello: 'world' })
103
+ })
104
+ })
105
+ })
106
+
107
+ test('fastify.register with fastify-plugin should provide access to external fastify instance if opts argument is a function', t => {
108
+ t.plan(22)
109
+ const fastify = Fastify()
110
+
111
+ fastify.register((instance, opts, done) => {
112
+ instance.register(fp((i, o, n) => {
113
+ i.decorate('global', () => {})
114
+ t.ok(i.global)
115
+ n()
116
+ }))
117
+
118
+ instance.register((i, o, n) => n(), p => {
119
+ t.notOk(p === instance || p === fastify)
120
+ t.ok(instance.isPrototypeOf(p))
121
+ t.ok(fastify.isPrototypeOf(p))
122
+ t.ok(p.global)
123
+ })
124
+
125
+ instance.register((i, o, n) => {
126
+ i.decorate('local', () => {})
127
+ n()
128
+ })
129
+
130
+ instance.register((i, o, n) => n(), p => t.notOk(p.local))
131
+
132
+ instance.register((i, o, n) => {
133
+ t.ok(i.local)
134
+ n()
135
+ }, p => p.decorate('local', () => {}))
136
+
137
+ instance.register((i, o, n) => n(), p => t.notOk(p.local))
138
+
139
+ instance.register(fp((i, o, n) => {
140
+ t.ok(i.global_2)
141
+ n()
142
+ }), p => p.decorate('global_2', () => 'hello'))
143
+
144
+ instance.register((i, o, n) => {
145
+ i.decorate('global_2', () => 'world')
146
+ n()
147
+ }, p => p.get('/', (req, reply) => {
148
+ t.ok(p.global_2)
149
+ reply.send({ hello: p.global_2() })
150
+ }))
151
+
152
+ t.notOk(instance.global)
153
+ t.notOk(instance.global_2)
154
+ t.notOk(instance.local)
155
+
156
+ // the decoration is added at the end
157
+ instance.after(() => {
158
+ t.ok(instance.global)
159
+ t.equal(instance.global_2(), 'hello')
160
+ t.notOk(instance.local)
161
+ })
162
+
163
+ done()
164
+ })
165
+
166
+ fastify.ready(() => {
167
+ t.notOk(fastify.global)
168
+ })
169
+
170
+ fastify.listen({ port: 0 }, err => {
171
+ t.error(err)
172
+ t.teardown(() => { fastify.close() })
173
+
174
+ sget({
175
+ method: 'GET',
176
+ url: 'http://localhost:' + fastify.server.address().port
177
+ }, (err, response, body) => {
178
+ t.error(err)
179
+ t.equal(response.statusCode, 200)
180
+ t.equal(response.headers['content-length'], '' + body.length)
181
+ t.same(JSON.parse(body), { hello: 'world' })
182
+ })
183
+ })
184
+ })
185
+
186
+ test('fastify.register with fastify-plugin registers fastify level plugins', t => {
187
+ t.plan(15)
188
+ const fastify = Fastify()
189
+
190
+ function fastifyPlugin (instance, opts, done) {
191
+ instance.decorate('test', 'first')
192
+ t.ok(instance.test)
193
+ done()
194
+ }
195
+
196
+ function innerPlugin (instance, opts, done) {
197
+ instance.decorate('test2', 'second')
198
+ done()
199
+ }
200
+
201
+ fastify.register(fp(fastifyPlugin))
202
+
203
+ fastify.register((instance, opts, done) => {
204
+ t.ok(instance.test)
205
+ instance.register(fp(innerPlugin))
206
+
207
+ instance.get('/test2', (req, reply) => {
208
+ t.ok(instance.test2)
209
+ reply.send({ test2: instance.test2 })
210
+ })
211
+
212
+ done()
213
+ })
214
+
215
+ fastify.ready(() => {
216
+ t.ok(fastify.test)
217
+ t.notOk(fastify.test2)
218
+ })
219
+
220
+ fastify.get('/', (req, reply) => {
221
+ t.ok(fastify.test)
222
+ reply.send({ test: fastify.test })
223
+ })
224
+
225
+ fastify.listen({ port: 0 }, err => {
226
+ t.error(err)
227
+ t.teardown(() => { fastify.close() })
228
+
229
+ sget({
230
+ method: 'GET',
231
+ url: 'http://localhost:' + fastify.server.address().port
232
+ }, (err, response, body) => {
233
+ t.error(err)
234
+ t.equal(response.statusCode, 200)
235
+ t.equal(response.headers['content-length'], '' + body.length)
236
+ t.same(JSON.parse(body), { test: 'first' })
237
+ })
238
+
239
+ sget({
240
+ method: 'GET',
241
+ url: 'http://localhost:' + fastify.server.address().port + '/test2'
242
+ }, (err, response, body) => {
243
+ t.error(err)
244
+ t.equal(response.statusCode, 200)
245
+ t.equal(response.headers['content-length'], '' + body.length)
246
+ t.same(JSON.parse(body), { test2: 'second' })
247
+ })
248
+ })
249
+ })
@@ -0,0 +1,328 @@
1
+ 'use strict'
2
+
3
+ /* eslint no-prototype-builtins: 0 */
4
+
5
+ const t = require('tap')
6
+ const test = t.test
7
+ const Fastify = require('../fastify')
8
+ const sget = require('simple-get').concat
9
+ const fp = require('fastify-plugin')
10
+
11
+ test('check dependencies - should not throw', t => {
12
+ t.plan(12)
13
+ const fastify = Fastify()
14
+
15
+ fastify.register((instance, opts, done) => {
16
+ instance.register(fp((i, o, n) => {
17
+ i.decorate('test', () => {})
18
+ t.ok(i.test)
19
+ n()
20
+ }))
21
+
22
+ instance.register(fp((i, o, n) => {
23
+ try {
24
+ i.decorate('otherTest', () => {}, ['test'])
25
+ t.ok(i.test)
26
+ t.ok(i.otherTest)
27
+ n()
28
+ } catch (e) {
29
+ t.fail()
30
+ }
31
+ }))
32
+
33
+ instance.get('/', (req, reply) => {
34
+ t.ok(instance.test)
35
+ t.ok(instance.otherTest)
36
+ reply.send({ hello: 'world' })
37
+ })
38
+
39
+ done()
40
+ })
41
+
42
+ fastify.ready(() => {
43
+ t.notOk(fastify.test)
44
+ t.notOk(fastify.otherTest)
45
+ })
46
+
47
+ fastify.listen({ port: 0 }, err => {
48
+ t.error(err)
49
+ t.teardown(() => { fastify.close() })
50
+
51
+ sget({
52
+ method: 'GET',
53
+ url: 'http://localhost:' + fastify.server.address().port
54
+ }, (err, response, body) => {
55
+ t.error(err)
56
+ t.equal(response.statusCode, 200)
57
+ t.equal(response.headers['content-length'], '' + body.length)
58
+ t.same(JSON.parse(body), { hello: 'world' })
59
+ })
60
+ })
61
+ })
62
+
63
+ test('check dependencies - should throw', t => {
64
+ t.plan(12)
65
+ const fastify = Fastify()
66
+
67
+ fastify.register((instance, opts, done) => {
68
+ instance.register(fp((i, o, n) => {
69
+ try {
70
+ i.decorate('otherTest', () => {}, ['test'])
71
+ t.fail()
72
+ } catch (e) {
73
+ t.equal(e.code, 'FST_ERR_DEC_MISSING_DEPENDENCY')
74
+ t.equal(e.message, 'The decorator is missing dependency \'test\'.')
75
+ }
76
+ n()
77
+ }))
78
+
79
+ instance.register(fp((i, o, n) => {
80
+ i.decorate('test', () => {})
81
+ t.ok(i.test)
82
+ t.notOk(i.otherTest)
83
+ n()
84
+ }))
85
+
86
+ instance.get('/', (req, reply) => {
87
+ t.ok(instance.test)
88
+ t.notOk(instance.otherTest)
89
+ reply.send({ hello: 'world' })
90
+ })
91
+
92
+ done()
93
+ })
94
+
95
+ fastify.ready(() => {
96
+ t.notOk(fastify.test)
97
+ })
98
+
99
+ fastify.listen({ port: 0 }, err => {
100
+ t.error(err)
101
+ t.teardown(() => { fastify.close() })
102
+
103
+ sget({
104
+ method: 'GET',
105
+ url: 'http://localhost:' + fastify.server.address().port
106
+ }, (err, response, body) => {
107
+ t.error(err)
108
+ t.equal(response.statusCode, 200)
109
+ t.equal(response.headers['content-length'], '' + body.length)
110
+ t.same(JSON.parse(body), { hello: 'world' })
111
+ })
112
+ })
113
+ })
114
+
115
+ test('set the plugin name based on the plugin displayName symbol', t => {
116
+ t.plan(6)
117
+ const fastify = Fastify()
118
+
119
+ fastify.register(fp((fastify, opts, done) => {
120
+ t.equal(fastify.pluginName, 'fastify -> plugin-A')
121
+ fastify.register(fp((fastify, opts, done) => {
122
+ t.equal(fastify.pluginName, 'fastify -> plugin-A -> plugin-AB')
123
+ done()
124
+ }, { name: 'plugin-AB' }))
125
+ fastify.register(fp((fastify, opts, done) => {
126
+ t.equal(fastify.pluginName, 'fastify -> plugin-A -> plugin-AB -> plugin-AC')
127
+ done()
128
+ }, { name: 'plugin-AC' }))
129
+ done()
130
+ }, { name: 'plugin-A' }))
131
+
132
+ fastify.register(fp((fastify, opts, done) => {
133
+ t.equal(fastify.pluginName, 'fastify -> plugin-A -> plugin-AB -> plugin-AC -> plugin-B')
134
+ done()
135
+ }, { name: 'plugin-B' }))
136
+
137
+ t.equal(fastify.pluginName, 'fastify')
138
+
139
+ fastify.listen({ port: 0 }, err => {
140
+ t.error(err)
141
+ fastify.close()
142
+ })
143
+ })
144
+
145
+ test('plugin name will change when using no encapsulation', t => {
146
+ t.plan(6)
147
+ const fastify = Fastify()
148
+
149
+ fastify.register(fp((fastify, opts, done) => {
150
+ // store it in a different variable will hold the correct name
151
+ const pluginName = fastify.pluginName
152
+ fastify.register(fp((fastify, opts, done) => {
153
+ t.equal(fastify.pluginName, 'fastify -> plugin-A -> plugin-AB')
154
+ done()
155
+ }, { name: 'plugin-AB' }))
156
+ fastify.register(fp((fastify, opts, done) => {
157
+ t.equal(fastify.pluginName, 'fastify -> plugin-A -> plugin-AB -> plugin-AC')
158
+ done()
159
+ }, { name: 'plugin-AC' }))
160
+ setImmediate(() => {
161
+ // normally we would expect the name plugin-A
162
+ // but we operate on the same instance in each plugin
163
+ t.equal(fastify.pluginName, 'fastify -> plugin-A -> plugin-AB -> plugin-AC')
164
+ t.equal(pluginName, 'fastify -> plugin-A')
165
+ })
166
+ done()
167
+ }, { name: 'plugin-A' }))
168
+
169
+ t.equal(fastify.pluginName, 'fastify')
170
+
171
+ fastify.listen({ port: 0 }, err => {
172
+ t.error(err)
173
+ fastify.close()
174
+ })
175
+ })
176
+
177
+ test('plugin name is undefined when accessing in no plugin context', t => {
178
+ t.plan(2)
179
+ const fastify = Fastify()
180
+
181
+ t.equal(fastify.pluginName, 'fastify')
182
+
183
+ fastify.listen({ port: 0 }, err => {
184
+ t.error(err)
185
+ fastify.close()
186
+ })
187
+ })
188
+
189
+ test('set the plugin name based on the plugin function name', t => {
190
+ t.plan(5)
191
+ const fastify = Fastify()
192
+
193
+ fastify.register(function myPluginA (fastify, opts, done) {
194
+ t.equal(fastify.pluginName, 'myPluginA')
195
+ fastify.register(function myPluginAB (fastify, opts, done) {
196
+ t.equal(fastify.pluginName, 'myPluginAB')
197
+ done()
198
+ })
199
+ setImmediate(() => {
200
+ // exact name due to encapsulation
201
+ t.equal(fastify.pluginName, 'myPluginA')
202
+ })
203
+ done()
204
+ })
205
+
206
+ fastify.register(function myPluginB (fastify, opts, done) {
207
+ t.equal(fastify.pluginName, 'myPluginB')
208
+ done()
209
+ })
210
+
211
+ fastify.listen({ port: 0 }, err => {
212
+ t.error(err)
213
+ fastify.close()
214
+ })
215
+ })
216
+
217
+ test('approximate a plugin name when no meta data is available', t => {
218
+ t.plan(7)
219
+ const fastify = Fastify()
220
+
221
+ fastify.register((fastify, opts, done) => {
222
+ // A
223
+ t.equal(fastify.pluginName.startsWith('(fastify, opts, done)'), true)
224
+ t.equal(fastify.pluginName.includes('// A'), true)
225
+ fastify.register((fastify, opts, done) => {
226
+ // B
227
+ t.equal(fastify.pluginName.startsWith('(fastify, opts, done)'), true)
228
+ t.equal(fastify.pluginName.includes('// B'), true)
229
+ done()
230
+ })
231
+ setImmediate(() => {
232
+ t.equal(fastify.pluginName.startsWith('(fastify, opts, done)'), true)
233
+ t.equal(fastify.pluginName.includes('// A'), true)
234
+ })
235
+ done()
236
+ })
237
+
238
+ fastify.listen({ port: 0 }, err => {
239
+ t.error(err)
240
+ fastify.close()
241
+ })
242
+ })
243
+
244
+ test('approximate a plugin name also when fastify-plugin has no meta data', t => {
245
+ t.plan(4)
246
+ const fastify = Fastify()
247
+ // plugin name is got from current file name
248
+ const pluginName = /plugin\.2\.test/
249
+ const pluginNameWithFunction = /plugin\.2\.test-auto-\d+ -> B/
250
+
251
+ fastify.register(fp((fastify, opts, done) => {
252
+ t.match(fastify.pluginName, pluginName)
253
+ fastify.register(fp(function B (fastify, opts, done) {
254
+ // function has name
255
+ t.match(fastify.pluginName, pluginNameWithFunction)
256
+ done()
257
+ }))
258
+ setImmediate(() => {
259
+ t.match(fastify.pluginName, pluginNameWithFunction)
260
+ })
261
+ done()
262
+ }))
263
+
264
+ fastify.listen({ port: 0 }, err => {
265
+ t.error(err)
266
+ fastify.close()
267
+ })
268
+ })
269
+
270
+ test('plugin encapsulation', t => {
271
+ t.plan(10)
272
+ const fastify = Fastify()
273
+
274
+ fastify.register((instance, opts, done) => {
275
+ instance.register(fp((i, o, n) => {
276
+ i.decorate('test', 'first')
277
+ n()
278
+ }))
279
+
280
+ instance.get('/first', (req, reply) => {
281
+ reply.send({ plugin: instance.test })
282
+ })
283
+
284
+ done()
285
+ })
286
+
287
+ fastify.register((instance, opts, done) => {
288
+ instance.register(fp((i, o, n) => {
289
+ i.decorate('test', 'second')
290
+ n()
291
+ }))
292
+
293
+ instance.get('/second', (req, reply) => {
294
+ reply.send({ plugin: instance.test })
295
+ })
296
+
297
+ done()
298
+ })
299
+
300
+ fastify.ready(() => {
301
+ t.notOk(fastify.test)
302
+ })
303
+
304
+ fastify.listen({ port: 0 }, err => {
305
+ t.error(err)
306
+ t.teardown(() => { fastify.close() })
307
+
308
+ sget({
309
+ method: 'GET',
310
+ url: 'http://localhost:' + fastify.server.address().port + '/first'
311
+ }, (err, response, body) => {
312
+ t.error(err)
313
+ t.equal(response.statusCode, 200)
314
+ t.equal(response.headers['content-length'], '' + body.length)
315
+ t.same(JSON.parse(body), { plugin: 'first' })
316
+ })
317
+
318
+ sget({
319
+ method: 'GET',
320
+ url: 'http://localhost:' + fastify.server.address().port + '/second'
321
+ }, (err, response, body) => {
322
+ t.error(err)
323
+ t.equal(response.statusCode, 200)
324
+ t.equal(response.headers['content-length'], '' + body.length)
325
+ t.same(JSON.parse(body), { plugin: 'second' })
326
+ })
327
+ })
328
+ })