fastify 4.0.1 → 4.1.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.
- package/.eslintrc +1 -0
- package/README.md +3 -3
- package/build/build-error-serializer.js +1 -0
- package/docs/Guides/Database.md +5 -5
- package/docs/Guides/Ecosystem.md +3 -0
- package/docs/Guides/Migration-Guide-V4.md +19 -2
- package/docs/Reference/LTS.md +2 -2
- package/docs/Reference/Server.md +1 -1
- package/docs/Reference/Type-Providers.md +4 -3
- package/fastify.d.ts +1 -1
- package/fastify.js +19 -19
- package/lib/error-serializer.js +175 -7
- package/lib/reply.js +3 -1
- package/lib/route.js +11 -11
- package/lib/server.js +9 -1
- package/lib/wrapThenable.js +8 -3
- package/package.json +6 -6
- package/test/404s.test.js +2 -2
- package/test/build/error-serializer.test.js +33 -0
- package/test/{internals → build}/version.test.js +1 -1
- package/test/internals/reply.test.js +12 -0
- package/test/listen.test.js +16 -2
- package/test/reply-error.test.js +7 -1
- package/test/stream.test.js +73 -0
- package/test/types/instance.test-d.ts +1 -1
- package/test/types/register.test-d.ts +77 -2
- package/types/register.d.ts +9 -7
- package/types/schema.d.ts +1 -1
package/.eslintrc
CHANGED
package/README.md
CHANGED
|
@@ -56,7 +56,7 @@ developer experience with the least overhead and a powerful plugin architecture.
|
|
|
56
56
|
It is inspired by Hapi and Express and as far as we know, it is one of the
|
|
57
57
|
fastest web frameworks in town.
|
|
58
58
|
|
|
59
|
-
This branch refers to the
|
|
59
|
+
This branch refers to the Fastify v4 release. Check out the
|
|
60
60
|
[v3.x](https://github.com/fastify/fastify/tree/v3.x) branch for v3.
|
|
61
61
|
|
|
62
62
|
### Quick start
|
|
@@ -104,11 +104,11 @@ project as a dependency:
|
|
|
104
104
|
|
|
105
105
|
Install with npm:
|
|
106
106
|
```sh
|
|
107
|
-
npm i fastify
|
|
107
|
+
npm i fastify
|
|
108
108
|
```
|
|
109
109
|
Install with yarn:
|
|
110
110
|
```sh
|
|
111
|
-
yarn add fastify
|
|
111
|
+
yarn add fastify
|
|
112
112
|
```
|
|
113
113
|
|
|
114
114
|
### Example
|
package/docs/Guides/Database.md
CHANGED
|
@@ -37,7 +37,7 @@ fastify.get('/user/:id', function(req, reply) {
|
|
|
37
37
|
)
|
|
38
38
|
})
|
|
39
39
|
|
|
40
|
-
fastify.listen(3000, err => {
|
|
40
|
+
fastify.listen({ port: 3000 }, err => {
|
|
41
41
|
if (err) throw err
|
|
42
42
|
console.log(`server listening on ${fastify.server.address().port}`)
|
|
43
43
|
})
|
|
@@ -64,7 +64,7 @@ fastify.get('/user/:id', function (req, reply) {
|
|
|
64
64
|
)
|
|
65
65
|
})
|
|
66
66
|
|
|
67
|
-
fastify.listen(3000, err => {
|
|
67
|
+
fastify.listen({ port: 3000 }, err => {
|
|
68
68
|
if (err) throw err
|
|
69
69
|
console.log(`server listening on ${fastify.server.address().port}`)
|
|
70
70
|
})
|
|
@@ -98,7 +98,7 @@ fastify.post('/foo', function (req, reply) {
|
|
|
98
98
|
})
|
|
99
99
|
})
|
|
100
100
|
|
|
101
|
-
fastify.listen(3000, err => {
|
|
101
|
+
fastify.listen({ port: 3000 }, err => {
|
|
102
102
|
if (err) throw err
|
|
103
103
|
console.log(`server listening on ${fastify.server.address().port}`)
|
|
104
104
|
})
|
|
@@ -145,7 +145,7 @@ fastify.get('/user/:id', function (req, reply) {
|
|
|
145
145
|
})
|
|
146
146
|
})
|
|
147
147
|
|
|
148
|
-
fastify.listen(3000, err => {
|
|
148
|
+
fastify.listen({ port: 3000 }, err => {
|
|
149
149
|
if (err) throw err
|
|
150
150
|
})
|
|
151
151
|
```
|
|
@@ -172,7 +172,7 @@ fastify.post('/foo', async function (req, reply) {
|
|
|
172
172
|
return { status: 'ok' }
|
|
173
173
|
})
|
|
174
174
|
|
|
175
|
-
fastify.listen(3000, err => {
|
|
175
|
+
fastify.listen({ port: 3000 }, err => {
|
|
176
176
|
if (err) throw err
|
|
177
177
|
console.log(`server listening on ${fastify.server.address().port}`)
|
|
178
178
|
})
|
package/docs/Guides/Ecosystem.md
CHANGED
|
@@ -346,6 +346,9 @@ section.
|
|
|
346
346
|
minification and transformation of responses.
|
|
347
347
|
- [`fastify-mongo-memory`](https://github.com/chapuletta/fastify-mongo-memory)
|
|
348
348
|
Fastify MongoDB in Memory Plugin for testing support.
|
|
349
|
+
- [`fastify-mongodb-sanitizer`](https://github.com/KlemenKozelj/fastify-mongodb-sanitizer)
|
|
350
|
+
Fastify plugin that sanitizes client input to prevent
|
|
351
|
+
potential MongoDB query injection attacks.
|
|
349
352
|
- [`fastify-mongoose-api`](https://github.com/jeka-kiselyov/fastify-mongoose-api)
|
|
350
353
|
Fastify plugin to create REST API methods based on Mongoose MongoDB models.
|
|
351
354
|
- [`fastify-mongoose-driver`](https://github.com/alex-ppg/fastify-mongoose)
|
|
@@ -14,14 +14,31 @@ Starting this version of Fastify, we have deprecated the use of `app.use()`. We
|
|
|
14
14
|
have decided not to support the use of middlewares. Both
|
|
15
15
|
[`@fastify/middie`](https://github.com/fastify/middie) and
|
|
16
16
|
[`@fastify/express`](https://github.com/fastify/fastify-express) will still be
|
|
17
|
-
there and maintained. Use Fastify's [hooks](
|
|
17
|
+
there and maintained. Use Fastify's [hooks](../Reference/Hooks.md) instead.
|
|
18
|
+
|
|
19
|
+
### `reply.res` moved to `reply.raw`
|
|
20
|
+
|
|
21
|
+
If you previously used the `reply.res` attribute to access the underlying Request
|
|
22
|
+
object you'll instead need to depend on `reply.raw`.
|
|
23
|
+
|
|
24
|
+
### Need to `return reply` to signal a "fork" of the promise chain
|
|
25
|
+
|
|
26
|
+
In some situations, like when a response is sent asynchronously or when you're
|
|
27
|
+
just not explicitly returning a response, you'll need to return the `reply`
|
|
28
|
+
argument from your router handler.
|
|
29
|
+
|
|
30
|
+
### `exposeHeadRoutes` true by default
|
|
31
|
+
|
|
32
|
+
Starting from v4, all the `GET` routes will create a sibling `HEAD` route.
|
|
33
|
+
You can revert this behaviour by setting the server's option `exposeHeadRoutes`
|
|
34
|
+
to `false`.
|
|
18
35
|
|
|
19
36
|
## Non Breaking Changes
|
|
20
37
|
|
|
21
38
|
### Change of schema for multiple types
|
|
22
39
|
|
|
23
40
|
|
|
24
|
-
Since
|
|
41
|
+
Since Fastify v4 has upgraded to Ajv v8. The "type" keywords with multiple types
|
|
25
42
|
(other than with "null") are prohibited. Read more
|
|
26
43
|
['here'](https://ajv.js.org/strict-mode.html#strict-types)
|
|
27
44
|
|
package/docs/Reference/LTS.md
CHANGED
|
@@ -47,8 +47,8 @@ A "month" is defined as 30 consecutive days.
|
|
|
47
47
|
| :------ | :----------- | :-------------- | :------------------- |
|
|
48
48
|
| 1.0.0 | 2018-03-06 | 2019-09-01 | 6, 8, 9, 10, 11 |
|
|
49
49
|
| 2.0.0 | 2019-02-25 | 2021-01-31 | 6, 8, 10, 12, 14 |
|
|
50
|
-
| 3.0.0 | 2020-07-07 |
|
|
51
|
-
| 4.0.0 |
|
|
50
|
+
| 3.0.0 | 2020-07-07 | 2023-06-30 | 10, 12, 14, 16, 18 |
|
|
51
|
+
| 4.0.0 | 2022-06-08 | TBD | 14, 16, 18 |
|
|
52
52
|
|
|
53
53
|
### CI tested operating systems
|
|
54
54
|
<a id="supported-os"></a>
|
package/docs/Reference/Server.md
CHANGED
|
@@ -1278,7 +1278,7 @@ const fastify = Fastify({
|
|
|
1278
1278
|
*/
|
|
1279
1279
|
bucket: function factory (parentSchemas) {
|
|
1280
1280
|
return {
|
|
1281
|
-
|
|
1281
|
+
add (inputSchema) {
|
|
1282
1282
|
// This function must store the schema added by the user.
|
|
1283
1283
|
// This function is invoked when `fastify.addSchema()` is called.
|
|
1284
1284
|
},
|
|
@@ -30,11 +30,11 @@ $ npm i @fastify/type-provider-json-schema-to-ts
|
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
```typescript
|
|
33
|
-
import {
|
|
33
|
+
import { JsonSchemaToTsProvider } from '@fastify/type-provider-json-schema-to-ts'
|
|
34
34
|
|
|
35
35
|
import fastify from 'fastify'
|
|
36
36
|
|
|
37
|
-
const server = fastify().withTypeProvider<
|
|
37
|
+
const server = fastify().withTypeProvider<JsonSchemaToTsProvider>()
|
|
38
38
|
|
|
39
39
|
server.get('/route', {
|
|
40
40
|
schema: {
|
|
@@ -65,7 +65,8 @@ $ npm i @fastify/type-provider-typebox
|
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
```typescript
|
|
68
|
-
import { TypeBoxTypeProvider
|
|
68
|
+
import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
|
|
69
|
+
import { Type } from '@sinclair/typebox'
|
|
69
70
|
|
|
70
71
|
import fastify from 'fastify'
|
|
71
72
|
|
package/fastify.d.ts
CHANGED
|
@@ -146,7 +146,7 @@ export type FastifyServerOptions<
|
|
|
146
146
|
},
|
|
147
147
|
schemaController?: {
|
|
148
148
|
bucket?: (parentSchemas?: unknown) => {
|
|
149
|
-
|
|
149
|
+
add(schema: unknown): FastifyInstance;
|
|
150
150
|
getSchema(schemaId: string): unknown;
|
|
151
151
|
getSchemas(): Record<string, unknown>;
|
|
152
152
|
};
|
package/fastify.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const VERSION = '4.0
|
|
3
|
+
const VERSION = '4.1.0'
|
|
4
4
|
|
|
5
5
|
const Avvio = require('avvio')
|
|
6
6
|
const http = require('http')
|
|
@@ -237,35 +237,35 @@ function fastify (options) {
|
|
|
237
237
|
getDefaultRoute: router.getDefaultRoute.bind(router),
|
|
238
238
|
setDefaultRoute: router.setDefaultRoute.bind(router),
|
|
239
239
|
// routes shorthand methods
|
|
240
|
-
delete: function _delete (url,
|
|
241
|
-
return router.prepareRoute.call(this, 'DELETE', url,
|
|
240
|
+
delete: function _delete (url, options, handler) {
|
|
241
|
+
return router.prepareRoute.call(this, { method: 'DELETE', url, options, handler })
|
|
242
242
|
},
|
|
243
|
-
get: function _get (url,
|
|
244
|
-
return router.prepareRoute.call(this, 'GET', url,
|
|
243
|
+
get: function _get (url, options, handler) {
|
|
244
|
+
return router.prepareRoute.call(this, { method: 'GET', url, options, handler })
|
|
245
245
|
},
|
|
246
|
-
head: function _head (url,
|
|
247
|
-
return router.prepareRoute.call(this, 'HEAD', url,
|
|
246
|
+
head: function _head (url, options, handler) {
|
|
247
|
+
return router.prepareRoute.call(this, { method: 'HEAD', url, options, handler })
|
|
248
248
|
},
|
|
249
|
-
patch: function _patch (url,
|
|
250
|
-
return router.prepareRoute.call(this, 'PATCH', url,
|
|
249
|
+
patch: function _patch (url, options, handler) {
|
|
250
|
+
return router.prepareRoute.call(this, { method: 'PATCH', url, options, handler })
|
|
251
251
|
},
|
|
252
|
-
post: function _post (url,
|
|
253
|
-
return router.prepareRoute.call(this, 'POST', url,
|
|
252
|
+
post: function _post (url, options, handler) {
|
|
253
|
+
return router.prepareRoute.call(this, { method: 'POST', url, options, handler })
|
|
254
254
|
},
|
|
255
|
-
put: function _put (url,
|
|
256
|
-
return router.prepareRoute.call(this, 'PUT', url,
|
|
255
|
+
put: function _put (url, options, handler) {
|
|
256
|
+
return router.prepareRoute.call(this, { method: 'PUT', url, options, handler })
|
|
257
257
|
},
|
|
258
|
-
options: function _options (url,
|
|
259
|
-
return router.prepareRoute.call(this, 'OPTIONS', url,
|
|
258
|
+
options: function _options (url, options, handler) {
|
|
259
|
+
return router.prepareRoute.call(this, { method: 'OPTIONS', url, options, handler })
|
|
260
260
|
},
|
|
261
|
-
all: function _all (url,
|
|
262
|
-
return router.prepareRoute.call(this, supportedMethods, url,
|
|
261
|
+
all: function _all (url, options, handler) {
|
|
262
|
+
return router.prepareRoute.call(this, { method: supportedMethods, url, options, handler })
|
|
263
263
|
},
|
|
264
264
|
// extended route
|
|
265
|
-
route: function _route (
|
|
265
|
+
route: function _route (options) {
|
|
266
266
|
// we need the fastify object that we are producing so we apply a lazy loading of the function,
|
|
267
267
|
// otherwise we should bind it after the declaration
|
|
268
|
-
return router.route.call(this,
|
|
268
|
+
return router.route.call(this, { options })
|
|
269
269
|
},
|
|
270
270
|
// expose logger instance
|
|
271
271
|
log: logger,
|
package/lib/error-serializer.js
CHANGED
|
@@ -1,15 +1,183 @@
|
|
|
1
1
|
// This file is autogenerated by build/build-error-serializer.js, do not edit
|
|
2
2
|
/* istanbul ignore file */
|
|
3
3
|
|
|
4
|
-
'use strict'
|
|
4
|
+
'use strict'
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Serializer {
|
|
9
|
+
constructor (options = {}) {
|
|
10
|
+
switch (options.rounding) {
|
|
11
|
+
case 'floor':
|
|
12
|
+
this.parseInteger = Math.floor
|
|
13
|
+
break
|
|
14
|
+
case 'ceil':
|
|
15
|
+
this.parseInteger = Math.ceil
|
|
16
|
+
break
|
|
17
|
+
case 'round':
|
|
18
|
+
this.parseInteger = Math.round
|
|
19
|
+
break
|
|
20
|
+
default:
|
|
21
|
+
this.parseInteger = Math.trunc
|
|
22
|
+
break
|
|
23
|
+
}
|
|
24
|
+
}
|
|
8
25
|
|
|
9
|
-
|
|
10
|
-
|
|
26
|
+
asAny (i) {
|
|
27
|
+
return JSON.stringify(i)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
asNull () {
|
|
31
|
+
return 'null'
|
|
32
|
+
}
|
|
11
33
|
|
|
34
|
+
asInteger (i) {
|
|
35
|
+
if (typeof i === 'bigint') {
|
|
36
|
+
return i.toString()
|
|
37
|
+
} else if (Number.isInteger(i)) {
|
|
38
|
+
return '' + i
|
|
39
|
+
} else {
|
|
40
|
+
/* eslint no-undef: "off" */
|
|
41
|
+
const integer = this.parseInteger(i)
|
|
42
|
+
if (Number.isNaN(integer)) {
|
|
43
|
+
throw new Error(`The value "${i}" cannot be converted to an integer.`)
|
|
44
|
+
} else {
|
|
45
|
+
return '' + integer
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
asIntegerNullable (i) {
|
|
51
|
+
return i === null ? 'null' : this.asInteger(i)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
asNumber (i) {
|
|
55
|
+
const num = Number(i)
|
|
56
|
+
if (Number.isNaN(num)) {
|
|
57
|
+
throw new Error(`The value "${i}" cannot be converted to a number.`)
|
|
58
|
+
} else {
|
|
59
|
+
return '' + num
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
asNumberNullable (i) {
|
|
64
|
+
return i === null ? 'null' : this.asNumber(i)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
asBoolean (bool) {
|
|
68
|
+
return bool && 'true' || 'false' // eslint-disable-line
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
asBooleanNullable (bool) {
|
|
72
|
+
return bool === null ? 'null' : this.asBoolean(bool)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
asDatetime (date, skipQuotes) {
|
|
76
|
+
const quotes = skipQuotes === true ? '' : '"'
|
|
77
|
+
if (date instanceof Date) {
|
|
78
|
+
return quotes + date.toISOString() + quotes
|
|
79
|
+
}
|
|
80
|
+
return this.asString(date, skipQuotes)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
asDatetimeNullable (date, skipQuotes) {
|
|
84
|
+
return date === null ? 'null' : this.asDatetime(date, skipQuotes)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
asDate (date, skipQuotes) {
|
|
88
|
+
const quotes = skipQuotes === true ? '' : '"'
|
|
89
|
+
if (date instanceof Date) {
|
|
90
|
+
return quotes + new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().slice(0, 10) + quotes
|
|
91
|
+
}
|
|
92
|
+
return this.asString(date, skipQuotes)
|
|
93
|
+
}
|
|
12
94
|
|
|
95
|
+
asDateNullable (date, skipQuotes) {
|
|
96
|
+
return date === null ? 'null' : this.asDate(date, skipQuotes)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
asTime (date, skipQuotes) {
|
|
100
|
+
const quotes = skipQuotes === true ? '' : '"'
|
|
101
|
+
if (date instanceof Date) {
|
|
102
|
+
return quotes + new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().slice(11, 19) + quotes
|
|
103
|
+
}
|
|
104
|
+
return this.asString(date, skipQuotes)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
asTimeNullable (date, skipQuotes) {
|
|
108
|
+
return date === null ? 'null' : this.asTime(date, skipQuotes)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
asString (str, skipQuotes) {
|
|
112
|
+
const quotes = skipQuotes === true ? '' : '"'
|
|
113
|
+
if (str instanceof Date) {
|
|
114
|
+
return quotes + str.toISOString() + quotes
|
|
115
|
+
} else if (str === null) {
|
|
116
|
+
return quotes + quotes
|
|
117
|
+
} else if (str instanceof RegExp) {
|
|
118
|
+
str = str.source
|
|
119
|
+
} else if (typeof str !== 'string') {
|
|
120
|
+
str = str.toString()
|
|
121
|
+
}
|
|
122
|
+
// If we skipQuotes it means that we are using it as test
|
|
123
|
+
// no need to test the string length for the render
|
|
124
|
+
if (skipQuotes) {
|
|
125
|
+
return str
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (str.length < 42) {
|
|
129
|
+
return this.asStringSmall(str)
|
|
130
|
+
} else {
|
|
131
|
+
return JSON.stringify(str)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
asStringNullable (str) {
|
|
136
|
+
return str === null ? 'null' : this.asString(str)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// magically escape strings for json
|
|
140
|
+
// relying on their charCodeAt
|
|
141
|
+
// everything below 32 needs JSON.stringify()
|
|
142
|
+
// every string that contain surrogate needs JSON.stringify()
|
|
143
|
+
// 34 and 92 happens all the time, so we
|
|
144
|
+
// have a fast case for them
|
|
145
|
+
asStringSmall (str) {
|
|
146
|
+
const l = str.length
|
|
147
|
+
let result = ''
|
|
148
|
+
let last = 0
|
|
149
|
+
let found = false
|
|
150
|
+
let surrogateFound = false
|
|
151
|
+
let point = 255
|
|
152
|
+
// eslint-disable-next-line
|
|
153
|
+
for (var i = 0; i < l && point >= 32; i++) {
|
|
154
|
+
point = str.charCodeAt(i)
|
|
155
|
+
if (point >= 0xD800 && point <= 0xDFFF) {
|
|
156
|
+
// The current character is a surrogate.
|
|
157
|
+
surrogateFound = true
|
|
158
|
+
}
|
|
159
|
+
if (point === 34 || point === 92) {
|
|
160
|
+
result += str.slice(last, i) + '\\'
|
|
161
|
+
last = i
|
|
162
|
+
found = true
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (!found) {
|
|
167
|
+
result = str
|
|
168
|
+
} else {
|
|
169
|
+
result += str.slice(last)
|
|
170
|
+
}
|
|
171
|
+
return ((point < 32) || (surrogateFound === true)) ? JSON.stringify(str) : '"' + result + '"'
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
const serializer = new Serializer({"mode":"standalone"})
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
|
|
13
181
|
function main (input) {
|
|
14
182
|
let json = ''
|
|
15
183
|
json += anonymous0(input)
|
|
@@ -81,5 +249,5 @@ const ajv = buildAjv({})
|
|
|
81
249
|
|
|
82
250
|
|
|
83
251
|
|
|
84
|
-
module.exports = main
|
|
85
|
-
|
|
252
|
+
module.exports = main
|
|
253
|
+
|
package/lib/reply.js
CHANGED
|
@@ -291,7 +291,7 @@ Reply.prototype.removeTrailer = function (key) {
|
|
|
291
291
|
|
|
292
292
|
Reply.prototype.code = function (code) {
|
|
293
293
|
const intValue = parseInt(code)
|
|
294
|
-
if (isNaN(intValue) || intValue < 100 || intValue >
|
|
294
|
+
if (isNaN(intValue) || intValue < 100 || intValue > 599) {
|
|
295
295
|
throw new FST_ERR_BAD_STATUS_CODE(code || String(code))
|
|
296
296
|
}
|
|
297
297
|
|
|
@@ -331,10 +331,12 @@ Reply.prototype.redirect = function (code, url) {
|
|
|
331
331
|
}
|
|
332
332
|
|
|
333
333
|
this.header('location', url).code(code).send()
|
|
334
|
+
return this
|
|
334
335
|
}
|
|
335
336
|
|
|
336
337
|
Reply.prototype.callNotFound = function () {
|
|
337
338
|
notFound(this)
|
|
339
|
+
return this
|
|
338
340
|
}
|
|
339
341
|
|
|
340
342
|
Reply.prototype.getResponseTime = function () {
|
package/lib/route.js
CHANGED
|
@@ -113,7 +113,7 @@ function buildRouting (options) {
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
// Convert shorthand to extended route declaration
|
|
116
|
-
function prepareRoute (method, url, options, handler) {
|
|
116
|
+
function prepareRoute ({ method, url, options, handler }) {
|
|
117
117
|
if (typeof url !== 'string') {
|
|
118
118
|
throw new FST_ERR_INVALID_URL(typeof url)
|
|
119
119
|
}
|
|
@@ -140,11 +140,11 @@ function buildRouting (options) {
|
|
|
140
140
|
handler: handler || (options && options.handler)
|
|
141
141
|
})
|
|
142
142
|
|
|
143
|
-
return route.call(this, options)
|
|
143
|
+
return route.call(this, { options })
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
// Route management
|
|
147
|
-
function route (options) {
|
|
147
|
+
function route ({ options }) {
|
|
148
148
|
// Since we are mutating/assigning only top level props, it is fine to have a shallow copy using the spread operator
|
|
149
149
|
const opts = { ...options }
|
|
150
150
|
|
|
@@ -176,30 +176,30 @@ function buildRouting (options) {
|
|
|
176
176
|
if (path === '/' && prefix.length > 0 && opts.method !== 'HEAD') {
|
|
177
177
|
switch (opts.prefixTrailingSlash) {
|
|
178
178
|
case 'slash':
|
|
179
|
-
addNewRoute.call(this, path)
|
|
179
|
+
addNewRoute.call(this, { path })
|
|
180
180
|
break
|
|
181
181
|
case 'no-slash':
|
|
182
|
-
addNewRoute.call(this, '')
|
|
182
|
+
addNewRoute.call(this, { path: '' })
|
|
183
183
|
break
|
|
184
184
|
case 'both':
|
|
185
185
|
default:
|
|
186
|
-
addNewRoute.call(this, '')
|
|
186
|
+
addNewRoute.call(this, { path: '' })
|
|
187
187
|
// If ignoreTrailingSlash is set to true we need to add only the '' route to prevent adding an incomplete one.
|
|
188
188
|
if (ignoreTrailingSlash !== true && (ignoreDuplicateSlashes !== true || !prefix.endsWith('/'))) {
|
|
189
|
-
addNewRoute.call(this, path, true)
|
|
189
|
+
addNewRoute.call(this, { path, prefixing: true })
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
192
|
} else if (path[0] === '/' && prefix.endsWith('/')) {
|
|
193
193
|
// Ensure that '/prefix/' + '/route' gets registered as '/prefix/route'
|
|
194
|
-
addNewRoute.call(this, path.slice(1))
|
|
194
|
+
addNewRoute.call(this, { path: path.slice(1) })
|
|
195
195
|
} else {
|
|
196
|
-
addNewRoute.call(this, path)
|
|
196
|
+
addNewRoute.call(this, { path })
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
// chainable api
|
|
200
200
|
return this
|
|
201
201
|
|
|
202
|
-
function addNewRoute (path, prefixing = false) {
|
|
202
|
+
function addNewRoute ({ path, prefixing = false }) {
|
|
203
203
|
const url = prefix + path
|
|
204
204
|
|
|
205
205
|
opts.url = url
|
|
@@ -326,7 +326,7 @@ function buildRouting (options) {
|
|
|
326
326
|
|
|
327
327
|
if (shouldExposeHead && options.method === 'GET' && !headRouteExists) {
|
|
328
328
|
const onSendHandlers = parseHeadOnSendHandlers(opts.onSend)
|
|
329
|
-
prepareRoute.call(this, 'HEAD', path, { ...opts, onSend: onSendHandlers })
|
|
329
|
+
prepareRoute.call(this, { method: 'HEAD', url: path, options: { ...opts, onSend: onSendHandlers } })
|
|
330
330
|
} else if (headRouteExists && exposeHeadRoute) {
|
|
331
331
|
warning.emit('FSTDEP007')
|
|
332
332
|
}
|
package/lib/server.js
CHANGED
|
@@ -41,7 +41,15 @@ function createServer (options, httpHandler) {
|
|
|
41
41
|
listenOptions.cb = cb
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
// If we have a path specified, don't default host to 'localhost' so we don't end up listening
|
|
45
|
+
// on both path and host
|
|
46
|
+
// See https://github.com/fastify/fastify/issues/4007
|
|
47
|
+
let host
|
|
48
|
+
if (listenOptions.path == null) {
|
|
49
|
+
host = listenOptions.host ?? 'localhost'
|
|
50
|
+
} else {
|
|
51
|
+
host = listenOptions.host
|
|
52
|
+
}
|
|
45
53
|
if (Object.prototype.hasOwnProperty.call(listenOptions, 'host') === false) {
|
|
46
54
|
listenOptions.host = host
|
|
47
55
|
}
|
package/lib/wrapThenable.js
CHANGED
|
@@ -11,9 +11,14 @@ function wrapThenable (thenable, reply) {
|
|
|
11
11
|
return
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
// this is for async functions that
|
|
15
|
-
//
|
|
16
|
-
|
|
14
|
+
// this is for async functions that are using reply.send directly
|
|
15
|
+
//
|
|
16
|
+
// since wrap-thenable will be called when using reply.send directly
|
|
17
|
+
// without actual return. the response can be sent already or
|
|
18
|
+
// the request may be terminated during the reply. in this situation,
|
|
19
|
+
// it require an extra checking of request.aborted to see whether
|
|
20
|
+
// the request is killed by client.
|
|
21
|
+
if (payload !== undefined || (reply.sent === false && reply.raw.headersSent === false && reply.request.raw.aborted === false)) {
|
|
17
22
|
// we use a try-catch internally to avoid adding a catch to another
|
|
18
23
|
// promise, increase promise perf by 10%
|
|
19
24
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fastify",
|
|
3
|
-
"version": "4.0
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "Fast and low overhead web framework, for Node.js",
|
|
5
5
|
"main": "fastify.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"lint:markdown": "markdownlint-cli2",
|
|
18
18
|
"lint:standard": "standard | snazzy",
|
|
19
19
|
"lint:typescript": "eslint -c types/.eslintrc.json types/**/*.d.ts test/types/**/*.test-d.ts",
|
|
20
|
-
"prepublishOnly": "tap --no-check-coverage test/
|
|
20
|
+
"prepublishOnly": "tap --no-check-coverage test/build/**.test.js",
|
|
21
21
|
"test": "npm run lint && npm run unit && npm run test:typescript",
|
|
22
22
|
"test:ci": "npm run unit -- -R terse --cov --coverage-report=lcovonly && npm run test:typescript",
|
|
23
23
|
"test:report": "npm run lint && npm run unit:report && npm run test:typescript",
|
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
"@fastify/pre-commit": "^2.0.2",
|
|
129
129
|
"@sinclair/typebox": "^0.23.5",
|
|
130
130
|
"@sinonjs/fake-timers": "^9.1.2",
|
|
131
|
-
"@types/node": "^
|
|
131
|
+
"@types/node": "^18.0.0",
|
|
132
132
|
"@typescript-eslint/eslint-plugin": "^5.27.0",
|
|
133
133
|
"@typescript-eslint/parser": "^5.27.0",
|
|
134
134
|
"ajv": "^8.11.0",
|
|
@@ -146,7 +146,7 @@
|
|
|
146
146
|
"eslint-plugin-n": "^15.2.0",
|
|
147
147
|
"eslint-plugin-promise": "^6.0.0",
|
|
148
148
|
"fast-json-body": "^1.1.0",
|
|
149
|
-
"fast-json-stringify": "^4.
|
|
149
|
+
"fast-json-stringify": "^4.2.0",
|
|
150
150
|
"fastify-plugin": "^3.0.1",
|
|
151
151
|
"fluent-json-schema": "^3.1.0",
|
|
152
152
|
"form-data": "^4.0.0",
|
|
@@ -170,7 +170,7 @@
|
|
|
170
170
|
"split2": "^4.1.0",
|
|
171
171
|
"standard": "^17.0.0-2",
|
|
172
172
|
"tap": "^16.2.0",
|
|
173
|
-
"tsd": "^0.
|
|
173
|
+
"tsd": "^0.21.0",
|
|
174
174
|
"typescript": "^4.7.2",
|
|
175
175
|
"undici": "^5.4.0",
|
|
176
176
|
"x-xss-protection": "^2.0.0",
|
|
@@ -179,7 +179,7 @@
|
|
|
179
179
|
"dependencies": {
|
|
180
180
|
"@fastify/ajv-compiler": "^3.1.0",
|
|
181
181
|
"@fastify/error": "^3.0.0",
|
|
182
|
-
"@fastify/fast-json-stringify-compiler": "^3.0.
|
|
182
|
+
"@fastify/fast-json-stringify-compiler": "^3.0.1",
|
|
183
183
|
"abstract-logging": "^2.0.1",
|
|
184
184
|
"avvio": "^8.1.3",
|
|
185
185
|
"find-my-way": "^6.3.0",
|
package/test/404s.test.js
CHANGED
|
@@ -1320,7 +1320,7 @@ test('preHandler option for setNotFoundHandler', t => {
|
|
|
1320
1320
|
|
|
1321
1321
|
// https://github.com/fastify/fastify/issues/2229
|
|
1322
1322
|
t.test('preHandler hook in setNotFoundHandler should be called when callNotFound', { timeout: 40000 }, t => {
|
|
1323
|
-
t.plan(
|
|
1323
|
+
t.plan(3)
|
|
1324
1324
|
const fastify = Fastify()
|
|
1325
1325
|
|
|
1326
1326
|
fastify.setNotFoundHandler({
|
|
@@ -1333,7 +1333,7 @@ test('preHandler option for setNotFoundHandler', t => {
|
|
|
1333
1333
|
})
|
|
1334
1334
|
|
|
1335
1335
|
fastify.post('/', function (req, reply) {
|
|
1336
|
-
reply.callNotFound()
|
|
1336
|
+
t.equal(reply.callNotFound(), reply)
|
|
1337
1337
|
})
|
|
1338
1338
|
|
|
1339
1339
|
fastify.inject({
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const t = require('tap')
|
|
4
|
+
const test = t.test
|
|
5
|
+
const fs = require('fs')
|
|
6
|
+
const path = require('path')
|
|
7
|
+
|
|
8
|
+
const { code } = require('../../build/build-error-serializer')
|
|
9
|
+
|
|
10
|
+
function unifyLineBreak (str) {
|
|
11
|
+
return str.toString().replace(/\r\n/g, '\n')
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
test('check generated code syntax', async (t) => {
|
|
15
|
+
t.plan(1)
|
|
16
|
+
|
|
17
|
+
// standard is a esm, we import it like this
|
|
18
|
+
const { default: standard } = await import('standard')
|
|
19
|
+
const result = await standard.lintText(code)
|
|
20
|
+
|
|
21
|
+
// if there are any invalid syntax
|
|
22
|
+
// fatal count will be greater than 0
|
|
23
|
+
t.equal(result[0].fatalErrorCount, 0)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test('ensure the current error serializer is latest', async (t) => {
|
|
27
|
+
t.plan(1)
|
|
28
|
+
|
|
29
|
+
const current = await fs.promises.readFile(path.resolve('lib/error-serializer.js'))
|
|
30
|
+
|
|
31
|
+
// line break should not be a problem depends on system
|
|
32
|
+
t.equal(unifyLineBreak(current), unifyLineBreak(code))
|
|
33
|
+
})
|
|
@@ -233,6 +233,10 @@ test('within an instance', t => {
|
|
|
233
233
|
reply.redirect('/')
|
|
234
234
|
})
|
|
235
235
|
|
|
236
|
+
fastify.get('/redirect-async', async function (req, reply) {
|
|
237
|
+
return reply.redirect('/')
|
|
238
|
+
})
|
|
239
|
+
|
|
236
240
|
fastify.get('/redirect-code', function (req, reply) {
|
|
237
241
|
reply.redirect(301, '/')
|
|
238
242
|
})
|
|
@@ -412,6 +416,14 @@ test('within an instance', t => {
|
|
|
412
416
|
})
|
|
413
417
|
})
|
|
414
418
|
|
|
419
|
+
test('redirect with async function to `/` - 10', t => {
|
|
420
|
+
t.plan(1)
|
|
421
|
+
|
|
422
|
+
http.get('http://localhost:' + fastify.server.address().port + '/redirect-async', function (response) {
|
|
423
|
+
t.equal(response.statusCode, 302)
|
|
424
|
+
})
|
|
425
|
+
})
|
|
426
|
+
|
|
415
427
|
t.end()
|
|
416
428
|
})
|
|
417
429
|
})
|
package/test/listen.test.js
CHANGED
|
@@ -196,14 +196,28 @@ if (os.platform() !== 'win32') {
|
|
|
196
196
|
const fastify = Fastify()
|
|
197
197
|
t.teardown(fastify.close.bind(fastify))
|
|
198
198
|
|
|
199
|
-
const sockFile = path.join(os.tmpdir(), `${(Math.random().toString(16) + '0000000').
|
|
199
|
+
const sockFile = path.join(os.tmpdir(), `${(Math.random().toString(16) + '0000000').slice(2, 10)}-server.sock`)
|
|
200
200
|
try {
|
|
201
201
|
fs.unlinkSync(sockFile)
|
|
202
202
|
} catch (e) { }
|
|
203
203
|
|
|
204
204
|
fastify.listen({ path: sockFile }, (err, address) => {
|
|
205
205
|
t.error(err)
|
|
206
|
-
t.
|
|
206
|
+
t.strictSame(fastify.addresses(), [sockFile])
|
|
207
|
+
t.equal(address, sockFile)
|
|
208
|
+
})
|
|
209
|
+
})
|
|
210
|
+
} else {
|
|
211
|
+
test('listen on socket', t => {
|
|
212
|
+
t.plan(3)
|
|
213
|
+
const fastify = Fastify()
|
|
214
|
+
t.teardown(fastify.close.bind(fastify))
|
|
215
|
+
|
|
216
|
+
const sockFile = `\\\\.\\pipe\\${(Math.random().toString(16) + '0000000').slice(2, 10)}-server-sock`
|
|
217
|
+
|
|
218
|
+
fastify.listen({ path: sockFile }, (err, address) => {
|
|
219
|
+
t.error(err)
|
|
220
|
+
t.strictSame(fastify.addresses(), [sockFile])
|
|
207
221
|
t.equal(address, sockFile)
|
|
208
222
|
})
|
|
209
223
|
})
|
package/test/reply-error.test.js
CHANGED
|
@@ -520,7 +520,13 @@ const invalidErrorCodes = [
|
|
|
520
520
|
undefined,
|
|
521
521
|
null,
|
|
522
522
|
'error_code',
|
|
523
|
-
|
|
523
|
+
|
|
524
|
+
// out of the 100-599 range:
|
|
525
|
+
0,
|
|
526
|
+
1,
|
|
527
|
+
99,
|
|
528
|
+
600,
|
|
529
|
+
700
|
|
524
530
|
]
|
|
525
531
|
invalidErrorCodes.forEach((invalidCode) => {
|
|
526
532
|
test(`should throw error if error code is ${invalidCode}`, t => {
|
package/test/stream.test.js
CHANGED
|
@@ -741,3 +741,76 @@ test('reply.send handles aborted requests', t => {
|
|
|
741
741
|
}, 1)
|
|
742
742
|
})
|
|
743
743
|
})
|
|
744
|
+
|
|
745
|
+
test('request terminated should not crash fastify', t => {
|
|
746
|
+
t.plan(10)
|
|
747
|
+
|
|
748
|
+
const spyLogger = {
|
|
749
|
+
level: 'error',
|
|
750
|
+
fatal: () => { },
|
|
751
|
+
error: () => {
|
|
752
|
+
t.fail('should not log an error')
|
|
753
|
+
},
|
|
754
|
+
warn: () => { },
|
|
755
|
+
info: () => { },
|
|
756
|
+
debug: () => { },
|
|
757
|
+
trace: () => { },
|
|
758
|
+
child: () => { return spyLogger }
|
|
759
|
+
}
|
|
760
|
+
const fastify = Fastify({
|
|
761
|
+
logger: spyLogger
|
|
762
|
+
})
|
|
763
|
+
|
|
764
|
+
fastify.get('/', async (req, reply) => {
|
|
765
|
+
const stream = new Readable()
|
|
766
|
+
stream._read = () => {}
|
|
767
|
+
reply.header('content-type', 'text/html; charset=utf-8')
|
|
768
|
+
reply.header('transfer-encoding', 'chunked')
|
|
769
|
+
stream.push('<h1>HTML</h1>')
|
|
770
|
+
|
|
771
|
+
reply.send(stream)
|
|
772
|
+
|
|
773
|
+
await new Promise((resolve) => { setTimeout(resolve, 100).unref() })
|
|
774
|
+
|
|
775
|
+
stream.push('<h1>should disply on second stream</h1>')
|
|
776
|
+
stream.push(null)
|
|
777
|
+
return reply
|
|
778
|
+
})
|
|
779
|
+
|
|
780
|
+
fastify.listen({ port: 0 }, err => {
|
|
781
|
+
t.error(err)
|
|
782
|
+
t.teardown(() => { fastify.close() })
|
|
783
|
+
|
|
784
|
+
const port = fastify.server.address().port
|
|
785
|
+
const http = require('http')
|
|
786
|
+
const req = http.get(`http://localhost:${port}`, function (res) {
|
|
787
|
+
const { statusCode, headers } = res
|
|
788
|
+
t.equal(statusCode, 200)
|
|
789
|
+
t.equal(headers['content-type'], 'text/html; charset=utf-8')
|
|
790
|
+
t.equal(headers['transfer-encoding'], 'chunked')
|
|
791
|
+
res.on('data', function (chunk) {
|
|
792
|
+
t.equal(chunk.toString(), '<h1>HTML</h1>')
|
|
793
|
+
})
|
|
794
|
+
|
|
795
|
+
setTimeout(() => {
|
|
796
|
+
req.destroy()
|
|
797
|
+
|
|
798
|
+
// the server is not crash, we can connect it
|
|
799
|
+
http.get(`http://localhost:${port}`, function (res) {
|
|
800
|
+
const { statusCode, headers } = res
|
|
801
|
+
t.equal(statusCode, 200)
|
|
802
|
+
t.equal(headers['content-type'], 'text/html; charset=utf-8')
|
|
803
|
+
t.equal(headers['transfer-encoding'], 'chunked')
|
|
804
|
+
let payload = ''
|
|
805
|
+
res.on('data', function (chunk) {
|
|
806
|
+
payload += chunk.toString()
|
|
807
|
+
})
|
|
808
|
+
res.on('end', function () {
|
|
809
|
+
t.equal(payload, '<h1>HTML</h1><h1>should disply on second stream</h1>')
|
|
810
|
+
t.pass('should end properly')
|
|
811
|
+
})
|
|
812
|
+
})
|
|
813
|
+
}, 1)
|
|
814
|
+
})
|
|
815
|
+
})
|
|
816
|
+
})
|
|
@@ -133,7 +133,7 @@ expectError(server.setErrorHandler(invalidErrorHandler))
|
|
|
133
133
|
server.setSchemaController({
|
|
134
134
|
bucket: (parentSchemas: unknown) => {
|
|
135
135
|
return {
|
|
136
|
-
|
|
136
|
+
add (schema: unknown) {
|
|
137
137
|
expectType<unknown>(schema)
|
|
138
138
|
expectType<FastifyInstance>(server.addSchema({ type: 'null' }))
|
|
139
139
|
return server.addSchema({ type: 'null' })
|
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
import { expectAssignable, expectError, expectType } from 'tsd'
|
|
2
|
-
import
|
|
2
|
+
import { IncomingMessage, Server, ServerResponse } from 'http'
|
|
3
|
+
import { Http2Server, Http2ServerRequest, Http2ServerResponse } from 'http2'
|
|
4
|
+
import fastify, { FastifyInstance, FastifyError, FastifyLoggerInstance, FastifyPluginAsync, FastifyPluginCallback, FastifyPluginOptions, RawServerDefault } from '../../fastify'
|
|
3
5
|
|
|
4
|
-
const
|
|
6
|
+
const testPluginCallback: FastifyPluginCallback = function (instance, opts, done) { }
|
|
7
|
+
const testPluginAsync: FastifyPluginAsync = async function (instance, opts) { }
|
|
8
|
+
|
|
9
|
+
const testPluginOpts: FastifyPluginCallback = function (instance, opts, done) { }
|
|
10
|
+
const testPluginOptsAsync: FastifyPluginAsync = async function (instance, opts) { }
|
|
11
|
+
|
|
12
|
+
const testPluginOptsWithType = (instance: FastifyInstance, opts: FastifyPluginOptions, done: (error?: FastifyError) => void) => { }
|
|
13
|
+
const testPluginOptsWithTypeAsync = async (instance: FastifyInstance, opts: FastifyPluginOptions) => { }
|
|
14
|
+
|
|
15
|
+
interface TestOptions extends FastifyPluginOptions {
|
|
16
|
+
option1: string;
|
|
17
|
+
option2: boolean;
|
|
18
|
+
}
|
|
5
19
|
|
|
6
20
|
// Type validation
|
|
7
21
|
expectError(fastify().register(testPluginOptsAsync, { prefix: 1 }))
|
|
@@ -26,3 +40,64 @@ expectAssignable<FastifyInstance>(
|
|
|
26
40
|
expectType<FastifyInstance>(instance)
|
|
27
41
|
})
|
|
28
42
|
)
|
|
43
|
+
|
|
44
|
+
// With Http2
|
|
45
|
+
const serverWithHttp2 = fastify({ http2: true })
|
|
46
|
+
type ServerWithHttp2 = FastifyInstance<Http2Server, Http2ServerRequest, Http2ServerResponse>
|
|
47
|
+
const testPluginWithHttp2: FastifyPluginCallback<TestOptions, Http2Server> = function (instance, opts, done) { }
|
|
48
|
+
const testPluginWithHttp2Async: FastifyPluginAsync<TestOptions, Http2Server> = async function (instance, opts) { }
|
|
49
|
+
const testPluginWithHttp2WithType = (instance: ServerWithHttp2, opts: FastifyPluginOptions, done: (error?: FastifyError) => void) => { }
|
|
50
|
+
const testPluginWithHttp2WithTypeAsync = async (instance: ServerWithHttp2, opts: FastifyPluginOptions) => { }
|
|
51
|
+
expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginCallback))
|
|
52
|
+
expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginAsync))
|
|
53
|
+
expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginOpts))
|
|
54
|
+
expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginOptsAsync))
|
|
55
|
+
expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginOptsWithType))
|
|
56
|
+
expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginOptsWithTypeAsync))
|
|
57
|
+
expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginWithHttp2))
|
|
58
|
+
expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginWithHttp2Async))
|
|
59
|
+
expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginWithHttp2WithType))
|
|
60
|
+
expectAssignable<ServerWithHttp2>(serverWithHttp2.register(testPluginWithHttp2WithTypeAsync))
|
|
61
|
+
expectAssignable<ServerWithHttp2>(serverWithHttp2.register((instance) => {
|
|
62
|
+
expectAssignable<FastifyInstance>(instance)
|
|
63
|
+
}))
|
|
64
|
+
expectAssignable<ServerWithHttp2>(serverWithHttp2.register((instance: ServerWithHttp2) => {
|
|
65
|
+
expectAssignable<ServerWithHttp2>(instance)
|
|
66
|
+
}))
|
|
67
|
+
expectAssignable<ServerWithHttp2>(serverWithHttp2.register(async (instance) => {
|
|
68
|
+
expectAssignable<FastifyInstance>(instance)
|
|
69
|
+
}))
|
|
70
|
+
expectAssignable<ServerWithHttp2>(serverWithHttp2.register(async (instance: ServerWithHttp2) => {
|
|
71
|
+
expectAssignable<ServerWithHttp2>(instance)
|
|
72
|
+
}))
|
|
73
|
+
|
|
74
|
+
// With Type Provider
|
|
75
|
+
type TestTypeProvider = { input: 'test', output: 'test' }
|
|
76
|
+
const serverWithTypeProvider = fastify().withTypeProvider<TestTypeProvider>()
|
|
77
|
+
type ServerWithTypeProvider = FastifyInstance<Server, IncomingMessage, ServerResponse, FastifyLoggerInstance, TestTypeProvider>
|
|
78
|
+
const testPluginWithTypeProvider: FastifyPluginCallback<TestOptions, RawServerDefault, TestTypeProvider> = function (instance, opts, done) { }
|
|
79
|
+
const testPluginWithTypeProviderAsync: FastifyPluginAsync<TestOptions, RawServerDefault, TestTypeProvider> = async function (instance, opts) { }
|
|
80
|
+
const testPluginWithTypeProviderWithType = (instance: ServerWithTypeProvider, opts: FastifyPluginOptions, done: (error?: FastifyError) => void) => { }
|
|
81
|
+
const testPluginWithTypeProviderWithTypeAsync = async (instance: ServerWithTypeProvider, opts: FastifyPluginOptions) => { }
|
|
82
|
+
expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginCallback))
|
|
83
|
+
expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginAsync))
|
|
84
|
+
expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginOpts))
|
|
85
|
+
expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginOptsAsync))
|
|
86
|
+
expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginOptsWithType))
|
|
87
|
+
expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginOptsWithTypeAsync))
|
|
88
|
+
expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginWithTypeProvider))
|
|
89
|
+
expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginWithTypeProviderAsync))
|
|
90
|
+
expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginWithTypeProviderWithType))
|
|
91
|
+
expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(testPluginWithTypeProviderWithTypeAsync))
|
|
92
|
+
expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register((instance) => {
|
|
93
|
+
expectAssignable<FastifyInstance>(instance)
|
|
94
|
+
}))
|
|
95
|
+
expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register((instance: ServerWithTypeProvider) => {
|
|
96
|
+
expectAssignable<ServerWithTypeProvider>(instance)
|
|
97
|
+
}))
|
|
98
|
+
expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(async (instance) => {
|
|
99
|
+
expectAssignable<FastifyInstance>(instance)
|
|
100
|
+
}))
|
|
101
|
+
expectAssignable<ServerWithTypeProvider>(serverWithTypeProvider.register(async (instance: ServerWithTypeProvider) => {
|
|
102
|
+
expectAssignable<ServerWithTypeProvider>(instance)
|
|
103
|
+
}))
|
package/types/register.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { FastifyPluginOptions, FastifyPluginCallback, FastifyPluginAsync } from './plugin'
|
|
2
2
|
import { LogLevel } from './logger'
|
|
3
3
|
import { FastifyInstance } from './instance'
|
|
4
|
+
import { RawServerBase } from './utils'
|
|
5
|
+
import { FastifyTypeProvider, RawServerDefault } from '../fastify'
|
|
4
6
|
|
|
5
7
|
export interface RegisterOptions {
|
|
6
8
|
prefix?: string;
|
|
@@ -15,17 +17,17 @@ export type FastifyRegisterOptions<Options> = (RegisterOptions & Options) | ((in
|
|
|
15
17
|
*
|
|
16
18
|
* Function for adding a plugin to fastify. The options are inferred from the passed in FastifyPlugin parameter.
|
|
17
19
|
*/
|
|
18
|
-
export interface FastifyRegister<T = void> {
|
|
19
|
-
<Options extends FastifyPluginOptions>(
|
|
20
|
-
plugin: FastifyPluginCallback<Options>,
|
|
20
|
+
export interface FastifyRegister<T = void, RawServer extends RawServerBase = RawServerDefault, TypeProviderDefault extends FastifyTypeProvider = FastifyTypeProvider> {
|
|
21
|
+
<Options extends FastifyPluginOptions, Server extends RawServerBase = RawServer, TypeProvider extends FastifyTypeProvider = TypeProviderDefault>(
|
|
22
|
+
plugin: FastifyPluginCallback<Options, Server, TypeProvider>,
|
|
21
23
|
opts?: FastifyRegisterOptions<Options>
|
|
22
24
|
): T;
|
|
23
|
-
<Options extends FastifyPluginOptions>(
|
|
24
|
-
plugin: FastifyPluginAsync<Options>,
|
|
25
|
+
<Options extends FastifyPluginOptions, Server extends RawServerBase = RawServer, TypeProvider extends FastifyTypeProvider = TypeProviderDefault>(
|
|
26
|
+
plugin: FastifyPluginAsync<Options, Server, TypeProvider>,
|
|
25
27
|
opts?: FastifyRegisterOptions<Options>
|
|
26
28
|
): T;
|
|
27
|
-
<Options extends FastifyPluginOptions>(
|
|
28
|
-
plugin: FastifyPluginCallback<Options> | FastifyPluginAsync<Options> | Promise<{ default: FastifyPluginCallback<Options> }> | Promise<{ default: FastifyPluginAsync<Options> }>,
|
|
29
|
+
<Options extends FastifyPluginOptions, Server extends RawServerBase = RawServer, TypeProvider extends FastifyTypeProvider = TypeProviderDefault>(
|
|
30
|
+
plugin: FastifyPluginCallback<Options, Server, TypeProvider> | FastifyPluginAsync<Options, Server, TypeProvider> | Promise<{ default: FastifyPluginCallback<Options, Server, TypeProvider> }> | Promise<{ default: FastifyPluginAsync<Options, Server, TypeProvider> }>,
|
|
29
31
|
opts?: FastifyRegisterOptions<Options>
|
|
30
32
|
): T;
|
|
31
33
|
}
|
package/types/schema.d.ts
CHANGED
|
@@ -41,7 +41,7 @@ export type FastifySerializerCompiler<T> = (routeSchema: FastifyRouteSchemaDef<T
|
|
|
41
41
|
|
|
42
42
|
export interface FastifySchemaControllerOptions{
|
|
43
43
|
bucket?: (parentSchemas?: unknown) => {
|
|
44
|
-
|
|
44
|
+
add(schema: unknown): FastifyInstance;
|
|
45
45
|
getSchema(schemaId: string): unknown;
|
|
46
46
|
getSchemas(): Record<string, unknown>;
|
|
47
47
|
};
|