fastify 3.27.2 → 4.0.0-alpha.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 (116) hide show
  1. package/README.md +5 -4
  2. package/build/build-error-serializer.js +27 -0
  3. package/build/build-validation.js +47 -35
  4. package/docs/Migration-Guide-V4.md +12 -0
  5. package/docs/Reference/ContentTypeParser.md +4 -0
  6. package/docs/Reference/Errors.md +51 -6
  7. package/docs/Reference/Hooks.md +4 -7
  8. package/docs/Reference/LTS.md +5 -4
  9. package/docs/Reference/Reply.md +23 -22
  10. package/docs/Reference/Request.md +1 -3
  11. package/docs/Reference/Routes.md +17 -10
  12. package/docs/Reference/Server.md +48 -63
  13. package/docs/Reference/TypeScript.md +11 -13
  14. package/docs/Reference/Validation-and-Serialization.md +28 -53
  15. package/docs/Type-Providers.md +257 -0
  16. package/examples/hooks.js +1 -1
  17. package/examples/simple-stream.js +18 -0
  18. package/fastify.d.ts +34 -22
  19. package/fastify.js +37 -35
  20. package/lib/configValidator.js +902 -1023
  21. package/lib/contentTypeParser.js +6 -16
  22. package/lib/context.js +36 -10
  23. package/lib/decorate.js +3 -1
  24. package/lib/error-handler.js +158 -0
  25. package/lib/error-serializer.js +257 -0
  26. package/lib/errors.js +43 -9
  27. package/lib/fourOhFour.js +31 -20
  28. package/lib/handleRequest.js +10 -13
  29. package/lib/hooks.js +14 -9
  30. package/lib/pluginOverride.js +0 -3
  31. package/lib/pluginUtils.js +3 -2
  32. package/lib/reply.js +28 -157
  33. package/lib/request.js +13 -10
  34. package/lib/route.js +131 -138
  35. package/lib/schema-controller.js +2 -2
  36. package/lib/schemas.js +27 -1
  37. package/lib/server.js +219 -116
  38. package/lib/symbols.js +4 -3
  39. package/lib/validation.js +2 -1
  40. package/lib/warnings.js +2 -12
  41. package/lib/wrapThenable.js +4 -11
  42. package/package.json +31 -35
  43. package/test/404s.test.js +243 -110
  44. package/test/500s.test.js +2 -2
  45. package/test/async-await.test.js +13 -69
  46. package/test/content-parser.test.js +32 -0
  47. package/test/context-config.test.js +52 -0
  48. package/test/custom-http-server.test.js +14 -7
  49. package/test/custom-parser-async.test.js +0 -65
  50. package/test/custom-parser.test.js +54 -121
  51. package/test/decorator.test.js +1 -3
  52. package/test/delete.test.js +5 -5
  53. package/test/encapsulated-error-handler.test.js +50 -0
  54. package/test/esm/index.test.js +0 -14
  55. package/test/fastify-instance.test.js +4 -4
  56. package/test/fluent-schema.test.js +4 -4
  57. package/test/get.test.js +3 -3
  58. package/test/helper.js +18 -3
  59. package/test/hooks-async.test.js +14 -47
  60. package/test/hooks.on-ready.test.js +9 -4
  61. package/test/hooks.test.js +58 -99
  62. package/test/http2/closing.test.js +5 -11
  63. package/test/http2/unknown-http-method.test.js +3 -9
  64. package/test/https/custom-https-server.test.js +12 -6
  65. package/test/input-validation.js +2 -2
  66. package/test/internals/handleRequest.test.js +3 -40
  67. package/test/internals/initialConfig.test.js +33 -12
  68. package/test/internals/reply.test.js +245 -3
  69. package/test/internals/request.test.js +13 -7
  70. package/test/internals/server.test.js +88 -0
  71. package/test/listen.test.js +84 -1
  72. package/test/logger.test.js +80 -40
  73. package/test/maxRequestsPerSocket.test.js +6 -4
  74. package/test/middleware.test.js +2 -25
  75. package/test/nullable-validation.test.js +51 -14
  76. package/test/plugin.test.js +31 -5
  77. package/test/pretty-print.test.js +22 -10
  78. package/test/reply-error.test.js +123 -12
  79. package/test/request-error.test.js +2 -5
  80. package/test/route-hooks.test.js +17 -17
  81. package/test/route-prefix.test.js +2 -1
  82. package/test/route.test.js +204 -20
  83. package/test/router-options.test.js +1 -1
  84. package/test/schema-examples.test.js +11 -5
  85. package/test/schema-feature.test.js +24 -19
  86. package/test/schema-serialization.test.js +9 -9
  87. package/test/schema-special-usage.test.js +14 -81
  88. package/test/schema-validation.test.js +9 -9
  89. package/test/skip-reply-send.test.js +1 -1
  90. package/test/stream.test.js +23 -12
  91. package/test/throw.test.js +8 -5
  92. package/test/type-provider.test.js +20 -0
  93. package/test/types/fastify.test-d.ts +10 -18
  94. package/test/types/import.js +2 -0
  95. package/test/types/import.ts +1 -0
  96. package/test/types/instance.test-d.ts +35 -14
  97. package/test/types/logger.test-d.ts +44 -15
  98. package/test/types/route.test-d.ts +8 -2
  99. package/test/types/schema.test-d.ts +2 -39
  100. package/test/types/type-provider.test-d.ts +417 -0
  101. package/test/validation-error-handling.test.js +8 -8
  102. package/test/versioned-routes.test.js +28 -16
  103. package/test/wrapThenable.test.js +7 -6
  104. package/types/content-type-parser.d.ts +17 -8
  105. package/types/hooks.d.ts +102 -59
  106. package/types/instance.d.ts +124 -104
  107. package/types/logger.d.ts +18 -104
  108. package/types/plugin.d.ts +10 -4
  109. package/types/reply.d.ts +16 -11
  110. package/types/request.d.ts +10 -5
  111. package/types/route.d.ts +42 -31
  112. package/types/schema.d.ts +1 -1
  113. package/types/type-provider.d.ts +99 -0
  114. package/types/utils.d.ts +1 -1
  115. package/lib/schema-compilers.js +0 -12
  116. package/test/emit-warning.test.js +0 -166
@@ -1,8 +1,15 @@
1
1
  import { expectType } from 'tsd'
2
- import fastify, { FastifyLogFn, LogLevel, FastifyLoggerInstance, FastifyError, FastifyRequest, FastifyReply } from '../../fastify'
2
+ import fastify, {
3
+ FastifyLogFn,
4
+ LogLevel,
5
+ FastifyLoggerInstance,
6
+ FastifyRequest,
7
+ FastifyReply,
8
+ FastifyBaseLogger
9
+ } from '../../fastify'
3
10
  import { Server, IncomingMessage, ServerResponse } from 'http'
4
- import pino from 'pino'
5
11
  import * as fs from 'fs'
12
+ import P from 'pino'
6
13
 
7
14
  expectType<FastifyLoggerInstance>(fastify().log)
8
15
 
@@ -15,14 +22,17 @@ class Foo {}
15
22
  expectType<void>(fastify<Server, IncomingMessage, ServerResponse, FastifyLoggerInstance>().log[logLevel as LogLevel]({ foo: 'bar' }))
16
23
  expectType<void>(fastify<Server, IncomingMessage, ServerResponse, FastifyLoggerInstance>().log[logLevel as LogLevel](new Error()))
17
24
  expectType<void>(fastify<Server, IncomingMessage, ServerResponse, FastifyLoggerInstance>().log[logLevel as LogLevel](new Foo()))
18
- expectType<void>(fastify<Server, IncomingMessage, ServerResponse, FastifyLoggerInstance>().log[logLevel as LogLevel](0))
19
25
  })
20
26
 
21
- interface CustomLogger extends FastifyLoggerInstance {
27
+ /*
28
+ // TODO make pino export BaseLogger again
29
+ interface CustomLogger extends FastifyBaseLogger {
22
30
  customMethod(msg: string, ...args: unknown[]): void;
23
31
  }
24
32
 
33
+ // // ToDo https://github.com/pinojs/pino/issues/1100
25
34
  class CustomLoggerImpl implements CustomLogger {
35
+ level = 'info'
26
36
  customMethod (msg: string, ...args: unknown[]) { console.log(msg, args) }
27
37
 
28
38
  // Implementation signature must be compatible with all overloads of FastifyLogFn
@@ -35,7 +45,9 @@ class CustomLoggerImpl implements CustomLogger {
35
45
  fatal (...args: unknown[]) { console.log(args) }
36
46
  trace (...args: unknown[]) { console.log(args) }
37
47
  debug (...args: unknown[]) { console.log(args) }
38
- child () { return new CustomLoggerImpl() }
48
+ silent (...args: unknown[]) { }
49
+
50
+ child (bindings: P.Bindings, options?: P.ChildLoggerOptions): CustomLoggerImpl { return new CustomLoggerImpl() }
39
51
  }
40
52
 
41
53
  const customLogger = new CustomLoggerImpl()
@@ -48,20 +60,21 @@ CustomLoggerImpl
48
60
  >({ logger: customLogger })
49
61
 
50
62
  expectType<CustomLoggerImpl>(serverWithCustomLogger.log)
63
+ */
51
64
 
52
65
  const serverWithPino = fastify<
53
66
  Server,
54
67
  IncomingMessage,
55
68
  ServerResponse,
56
- pino.Logger
69
+ P.Logger
57
70
  >({
58
- logger: pino({
71
+ logger: P({
59
72
  level: 'info',
60
73
  redact: ['x-userinfo']
61
74
  })
62
75
  })
63
76
 
64
- expectType<pino.Logger>(serverWithPino.log)
77
+ expectType<P.Logger>(serverWithPino.log)
65
78
 
66
79
  const serverWithLogOptions = fastify<
67
80
  Server,
@@ -94,16 +107,16 @@ const serverAutoInferringTypes = fastify({
94
107
  }
95
108
  })
96
109
 
97
- expectType<FastifyLoggerInstance>(serverAutoInferringTypes.log)
110
+ expectType<FastifyBaseLogger>(serverAutoInferringTypes.log)
98
111
 
99
112
  const serverWithAutoInferredPino = fastify({
100
- logger: pino({
113
+ logger: P({
101
114
  level: 'info',
102
115
  redact: ['x-userinfo']
103
116
  })
104
117
  })
105
118
 
106
- expectType<pino.Logger>(serverWithAutoInferredPino.log)
119
+ expectType<P.Logger>(serverWithAutoInferredPino.log)
107
120
 
108
121
  const serverAutoInferredFileOption = fastify({
109
122
  logger: {
@@ -112,7 +125,7 @@ const serverAutoInferredFileOption = fastify({
112
125
  }
113
126
  })
114
127
 
115
- expectType<FastifyLoggerInstance>(serverAutoInferredFileOption.log)
128
+ expectType<FastifyBaseLogger>(serverAutoInferredFileOption.log)
116
129
 
117
130
  const serverAutoInferredPinoPrettyBooleanOption = fastify({
118
131
  logger: {
@@ -120,7 +133,7 @@ const serverAutoInferredPinoPrettyBooleanOption = fastify({
120
133
  }
121
134
  })
122
135
 
123
- expectType<FastifyLoggerInstance>(serverAutoInferredPinoPrettyBooleanOption.log)
136
+ expectType<FastifyBaseLogger>(serverAutoInferredPinoPrettyBooleanOption.log)
124
137
 
125
138
  const serverAutoInferredPinoPrettyObjectOption = fastify({
126
139
  logger: {
@@ -141,7 +154,7 @@ const serverAutoInferredPinoPrettyObjectOption = fastify({
141
154
  }
142
155
  })
143
156
 
144
- expectType<FastifyLoggerInstance>(serverAutoInferredPinoPrettyObjectOption.log)
157
+ expectType<FastifyBaseLogger>(serverAutoInferredPinoPrettyObjectOption.log)
145
158
 
146
159
  const serverAutoInferredSerializerObjectOption = fastify({
147
160
  logger: {
@@ -176,10 +189,26 @@ const serverAutoInferredSerializerObjectOption = fastify({
176
189
  }
177
190
  })
178
191
 
179
- expectType<FastifyLoggerInstance>(serverAutoInferredSerializerObjectOption.log)
192
+ expectType<FastifyBaseLogger>(serverAutoInferredSerializerObjectOption.log)
180
193
 
181
194
  const passStreamAsOption = fastify({
182
195
  logger: {
183
196
  stream: fs.createWriteStream('/tmp/stream.out')
184
197
  }
185
198
  })
199
+
200
+ expectType<FastifyBaseLogger>(passStreamAsOption.log)
201
+
202
+ const passPinoOption = fastify({
203
+ logger: {
204
+ redact: ['custom'],
205
+ messageKey: 'msg',
206
+ nestedKey: 'nested',
207
+ prettyPrint: {
208
+
209
+ },
210
+ enabled: true
211
+ }
212
+ })
213
+
214
+ expectType<FastifyBaseLogger>(passPinoOption.log)
@@ -1,5 +1,5 @@
1
1
  import fastify, { FastifyInstance, FastifyRequest, FastifyReply, RouteHandlerMethod } from '../../fastify'
2
- import { expectType, expectError, expectAssignable } from 'tsd'
2
+ import { expectType, expectError, expectAssignable, printType } from 'tsd'
3
3
  import { HTTPMethods } from '../../types/utils'
4
4
  import * as http from 'http'
5
5
  import { RequestPayload } from '../../types/hooks'
@@ -44,7 +44,13 @@ type LowerCaseHTTPMethods = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete'
44
44
  expectType<FastifyInstance>(fastify()[lowerCaseMethod]('/', {}, routeHandler))
45
45
  expectType<FastifyInstance>(fastify()[lowerCaseMethod]('/', { handler: routeHandler }))
46
46
 
47
- expectType<FastifyInstance>(fastify()[lowerCaseMethod]('/', { handler: routeHandler, errorHandler: (error, request, reply) => reply.send('error') }))
47
+ expectType<FastifyInstance>(fastify()[lowerCaseMethod]('/', {
48
+ handler: routeHandler,
49
+ errorHandler: (error, request, reply) => {
50
+ expectType<FastifyError>(error)
51
+ reply.send('error')
52
+ }
53
+ }))
48
54
 
49
55
  interface BodyInterface { prop: string }
50
56
  interface QuerystringInterface { prop: number }
@@ -3,7 +3,7 @@ import fastify, { FastifyInstance, FastifyRequest, FastifySchema } from '../../f
3
3
  import { RouteGenericInterface } from '../../types/route'
4
4
  import { ContextConfigDefault } from '../../types/utils'
5
5
  import { FastifyReply } from '../../types/reply'
6
- import Ajv = require('ajv')
6
+ import Ajv from 'ajv'
7
7
 
8
8
  const server = fastify()
9
9
 
@@ -35,33 +35,6 @@ expectAssignable<FastifyInstance>(server.get(
35
35
  () => { }
36
36
  ))
37
37
 
38
- expectAssignable<FastifyInstance>(server.get<RouteGenericInterface, ContextConfigDefault, { validate:(data: any) => any }>(
39
- '/no-schema',
40
- {
41
- schema: {},
42
- validatorCompiler: ({ schema }) => {
43
- // Error: Property 'validate' does not exist on type 'FastifySchema'.
44
- return (data: any) => schema.validate(data)
45
- }
46
- },
47
- () => { }
48
- ))
49
-
50
- expectAssignable<FastifyInstance>(
51
- server.route<RouteGenericInterface, ContextConfigDefault, { validate:(data: any) => any }>(
52
- {
53
- schema: {},
54
- validatorCompiler: ({ schema }) => {
55
- // Error: Property 'validate' does not exist on type 'FastifySchema'.
56
- return (data: any) => schema.validate(data)
57
- },
58
- method: 'POST',
59
- url: '/',
60
- handler: async (_request: FastifyRequest, _reply: FastifyReply) => {}
61
- }
62
- )
63
- )
64
-
65
38
  expectAssignable<FastifyInstance>(server.setValidatorCompiler(({ schema }) => {
66
39
  return new Ajv().compile(schema)
67
40
  }))
@@ -83,20 +56,10 @@ expectAssignable<FastifyInstance>(server.post('/test', {
83
56
 
84
57
  expectAssignable<FastifyInstance>(server.setValidatorCompiler<FastifySchema & { validate: Record<string, unknown> }>(
85
58
  function ({ schema }) {
86
- return new Ajv().compile(schema.validate)
59
+ return new Ajv().compile(schema)
87
60
  }
88
61
  ))
89
62
 
90
63
  expectAssignable<FastifyInstance>(server.setSerializerCompiler<FastifySchema & { validate: string }>(
91
64
  () => data => JSON.stringify(data)
92
65
  ))
93
-
94
- expectError(server.get(
95
- '/unknown-schema-prop',
96
- {
97
- schema: {
98
- unknown: { type: 'null' }
99
- }
100
- },
101
- () => { }
102
- ))
@@ -0,0 +1,417 @@
1
+ import fastify, { FastifyTypeProvider } from '../../fastify'
2
+ import { expectAssignable, expectError, expectType } from 'tsd'
3
+ import { IncomingHttpHeaders } from 'http'
4
+ import { Type, TSchema, Static } from '@sinclair/typebox'
5
+ import { FromSchema, JSONSchema } from 'json-schema-to-ts'
6
+
7
+ const server = fastify()
8
+
9
+ // -------------------------------------------------------------------
10
+ // Remapping
11
+ // -------------------------------------------------------------------
12
+
13
+ interface NumberProvider extends FastifyTypeProvider { output: number } // remap all schemas to numbers
14
+
15
+ expectAssignable(server.withTypeProvider<NumberProvider>().get(
16
+ '/',
17
+ {
18
+ schema: {
19
+ body: { type: 'string' },
20
+ querystring: { type: 'string' },
21
+ headers: { type: 'string' },
22
+ params: { type: 'string' }
23
+ }
24
+ },
25
+ (req) => {
26
+ expectType<number & IncomingHttpHeaders>(req.headers)
27
+ expectType<number>(req.body)
28
+ expectType<number>(req.query)
29
+ expectType<number>(req.params)
30
+ }
31
+ ))
32
+
33
+ // -------------------------------------------------------------------
34
+ // Override
35
+ // -------------------------------------------------------------------
36
+
37
+ interface OverriddenProvider extends FastifyTypeProvider { output: 'inferenced' }
38
+
39
+ expectAssignable(server.withTypeProvider<OverriddenProvider>().get<{ Body: 'override' }>(
40
+ '/',
41
+ {
42
+ schema: {
43
+ body: Type.Object({
44
+ x: Type.Number(),
45
+ y: Type.Number(),
46
+ z: Type.Number()
47
+ })
48
+ }
49
+ },
50
+ (req) => {
51
+ expectType<'override'>(req.body)
52
+ }
53
+ ))
54
+
55
+ // -------------------------------------------------------------------
56
+ // TypeBox
57
+ // -------------------------------------------------------------------
58
+
59
+ interface TypeBoxProvider extends FastifyTypeProvider { output: this['input'] extends TSchema ? Static<this['input']> : never }
60
+
61
+ expectAssignable(server.withTypeProvider<TypeBoxProvider>().get(
62
+ '/',
63
+ {
64
+ schema: {
65
+ body: Type.Object({
66
+ x: Type.Number(),
67
+ y: Type.Number(),
68
+ z: Type.Number()
69
+ })
70
+ }
71
+ },
72
+ (req) => {
73
+ expectType<number>(req.body.x)
74
+ expectType<number>(req.body.y)
75
+ expectType<number>(req.body.z)
76
+ }
77
+ ))
78
+
79
+ // -------------------------------------------------------------------
80
+ // JsonSchemaToTs
81
+ // -------------------------------------------------------------------
82
+
83
+ interface JsonSchemaToTsProvider extends FastifyTypeProvider { output: this['input'] extends JSONSchema ? FromSchema<this['input']> : never }
84
+
85
+ expectAssignable(server.withTypeProvider<JsonSchemaToTsProvider>().get(
86
+ '/',
87
+ {
88
+ schema: {
89
+ body: {
90
+ type: 'object',
91
+ properties: {
92
+ x: { type: 'number' },
93
+ y: { type: 'string' },
94
+ z: { type: 'boolean' }
95
+ }
96
+ } as const
97
+ }
98
+ },
99
+ (req) => {
100
+ expectType<number | undefined>(req.body.x)
101
+ expectType<string | undefined>(req.body.y)
102
+ expectType<boolean | undefined>(req.body.z)
103
+ }
104
+ ))
105
+
106
+ // -------------------------------------------------------------------
107
+ // Instance Type Remappable
108
+ // -------------------------------------------------------------------
109
+
110
+ expectAssignable(server.withTypeProvider<TypeBoxProvider>().withTypeProvider<JsonSchemaToTsProvider>().get(
111
+ '/',
112
+ {
113
+ schema: {
114
+ body: {
115
+ type: 'object',
116
+ properties: {
117
+ x: { type: 'number' },
118
+ y: { type: 'string' },
119
+ z: { type: 'boolean' }
120
+ }
121
+ } as const
122
+ }
123
+ },
124
+ (req) => {
125
+ expectType<number | undefined>(req.body.x)
126
+ expectType<string | undefined>(req.body.y)
127
+ expectType<boolean | undefined>(req.body.z)
128
+ }
129
+ ))
130
+
131
+ // -------------------------------------------------------------------
132
+ // Request Hooks
133
+ // -------------------------------------------------------------------
134
+
135
+ expectAssignable(server.withTypeProvider<TypeBoxProvider>().get(
136
+ '/',
137
+ {
138
+ schema: {
139
+ body: Type.Object({
140
+ x: Type.Number(),
141
+ y: Type.String(),
142
+ z: Type.Boolean()
143
+ })
144
+ },
145
+ preHandler: req => {
146
+ expectType<number>(req.body.x)
147
+ expectType<string>(req.body.y)
148
+ expectType<boolean>(req.body.z)
149
+ },
150
+ preParsing: req => {
151
+ expectType<number>(req.body.x)
152
+ expectType<string>(req.body.y)
153
+ expectType<boolean>(req.body.z)
154
+ },
155
+ preSerialization: req => {
156
+ expectType<number>(req.body.x)
157
+ expectType<string>(req.body.y)
158
+ expectType<boolean>(req.body.z)
159
+ },
160
+ preValidation: req => {
161
+ expectType<number>(req.body.x)
162
+ expectType<string>(req.body.y)
163
+ expectType<boolean>(req.body.z)
164
+ },
165
+ onError: req => {
166
+ expectType<number>(req.body.x)
167
+ expectType<string>(req.body.y)
168
+ expectType<boolean>(req.body.z)
169
+ },
170
+ onRequest: req => {
171
+ expectType<number>(req.body.x)
172
+ expectType<string>(req.body.y)
173
+ expectType<boolean>(req.body.z)
174
+ },
175
+ onResponse: req => {
176
+ expectType<number>(req.body.x)
177
+ expectType<string>(req.body.y)
178
+ expectType<boolean>(req.body.z)
179
+ },
180
+ onTimeout: req => {
181
+ expectType<number>(req.body.x)
182
+ expectType<string>(req.body.y)
183
+ expectType<boolean>(req.body.z)
184
+ },
185
+ onSend: req => {
186
+ expectType<number>(req.body.x)
187
+ expectType<string>(req.body.y)
188
+ expectType<boolean>(req.body.z)
189
+ }
190
+ },
191
+ req => {
192
+ expectType<number>(req.body.x)
193
+ expectType<string>(req.body.y)
194
+ expectType<boolean>(req.body.z)
195
+ }
196
+ ))
197
+
198
+ // -------------------------------------------------------------------
199
+ // TypeBox Reply Type
200
+ // -------------------------------------------------------------------
201
+
202
+ expectAssignable(server.withTypeProvider<TypeBoxProvider>().get(
203
+ '/',
204
+ {
205
+ schema: {
206
+ response: {
207
+ 200: Type.String(),
208
+ 400: Type.Number(),
209
+ 500: Type.Object({
210
+ error: Type.String()
211
+ })
212
+ }
213
+ }
214
+ },
215
+ async (_, res) => {
216
+ res.send('hello')
217
+ res.send(42)
218
+ res.send({ error: 'error' })
219
+ }
220
+ ))
221
+
222
+ // -------------------------------------------------------------------
223
+ // TypeBox Reply Type: Non Assignable
224
+ // -------------------------------------------------------------------
225
+
226
+ expectError(server.withTypeProvider<TypeBoxProvider>().get(
227
+ '/',
228
+ {
229
+ schema: {
230
+ response: {
231
+ 200: Type.String(),
232
+ 400: Type.Number(),
233
+ 500: Type.Object({
234
+ error: Type.String()
235
+ })
236
+ }
237
+ }
238
+ },
239
+ async (_, res) => {
240
+ res.send(false)
241
+ }
242
+ ))
243
+
244
+ // -------------------------------------------------------------------
245
+ // TypeBox Reply Return Type
246
+ // -------------------------------------------------------------------
247
+
248
+ expectAssignable(server.withTypeProvider<TypeBoxProvider>().get(
249
+ '/',
250
+ {
251
+ schema: {
252
+ response: {
253
+ 200: Type.String(),
254
+ 400: Type.Number(),
255
+ 500: Type.Object({
256
+ error: Type.String()
257
+ })
258
+ }
259
+ }
260
+ },
261
+ async (_, res) => {
262
+ const option = 1 as 1 | 2 | 3
263
+ switch (option) {
264
+ case 1: return 'hello'
265
+ case 2: return 42
266
+ case 3: return { error: 'error' }
267
+ }
268
+ }
269
+ ))
270
+
271
+ // -------------------------------------------------------------------
272
+ // TypeBox Reply Return Type: Non Assignable
273
+ // -------------------------------------------------------------------
274
+
275
+ expectError(server.withTypeProvider<TypeBoxProvider>().get(
276
+ '/',
277
+ {
278
+ schema: {
279
+ response: {
280
+ 200: Type.String(),
281
+ 400: Type.Number(),
282
+ 500: Type.Object({
283
+ error: Type.String()
284
+ })
285
+ }
286
+ }
287
+ },
288
+ async (_, res) => {
289
+ return false
290
+ }
291
+ ))
292
+
293
+ // -------------------------------------------------------------------
294
+ // JsonSchemaToTs Reply Type
295
+ // -------------------------------------------------------------------
296
+
297
+ expectAssignable(server.withTypeProvider<JsonSchemaToTsProvider>().get(
298
+ '/',
299
+ {
300
+ schema: {
301
+ response: {
302
+ 200: { type: 'string' },
303
+ 400: { type: 'number' },
304
+ 500: { type: 'object', properties: { error: { type: 'string' } } }
305
+ } as const
306
+ }
307
+ },
308
+ (_, res) => {
309
+ res.send('hello')
310
+ res.send(42)
311
+ res.send({ error: 'error' })
312
+ }
313
+ ))
314
+
315
+ // -------------------------------------------------------------------
316
+ // JsonSchemaToTs Reply Type: Non Assignable
317
+ // -------------------------------------------------------------------
318
+
319
+ expectError(server.withTypeProvider<JsonSchemaToTsProvider>().get(
320
+ '/',
321
+ {
322
+ schema: {
323
+ response: {
324
+ 200: { type: 'string' },
325
+ 400: { type: 'number' },
326
+ 500: { type: 'object', properties: { error: { type: 'string' } } }
327
+ } as const
328
+ }
329
+ },
330
+ async (_, res) => {
331
+ res.send(false)
332
+ }
333
+ ))
334
+
335
+ // -------------------------------------------------------------------
336
+ // JsonSchemaToTs Reply Type Return
337
+ // -------------------------------------------------------------------
338
+
339
+ expectAssignable(server.withTypeProvider<JsonSchemaToTsProvider>().get(
340
+ '/',
341
+ {
342
+ schema: {
343
+ response: {
344
+ 200: { type: 'string' },
345
+ 400: { type: 'number' },
346
+ 500: { type: 'object', properties: { error: { type: 'string' } } }
347
+ } as const
348
+ }
349
+ },
350
+ async (_, res) => {
351
+ const option = 1 as 1 | 2 | 3
352
+ switch (option) {
353
+ case 1: return 'hello'
354
+ case 2: return 42
355
+ case 3: return { error: 'error' }
356
+ }
357
+ }
358
+ ))
359
+ // -------------------------------------------------------------------
360
+ // JsonSchemaToTs Reply Type Return: Non Assignable
361
+ // -------------------------------------------------------------------
362
+
363
+ expectError(server.withTypeProvider<JsonSchemaToTsProvider>().get(
364
+ '/',
365
+ {
366
+ schema: {
367
+ response: {
368
+ 200: { type: 'string' },
369
+ 400: { type: 'number' },
370
+ 500: { type: 'object', properties: { error: { type: 'string' } } }
371
+ } as const
372
+ }
373
+ },
374
+ async (_, res) => {
375
+ return false
376
+ }
377
+ ))
378
+
379
+ // -------------------------------------------------------------------
380
+ // Reply Type Override
381
+ // -------------------------------------------------------------------
382
+
383
+ expectAssignable(server.withTypeProvider<JsonSchemaToTsProvider>().get<{Reply: boolean}>(
384
+ '/',
385
+ {
386
+ schema: {
387
+ response: {
388
+ 200: { type: 'string' },
389
+ 400: { type: 'number' },
390
+ 500: { type: 'object', properties: { error: { type: 'string' } } }
391
+ } as const
392
+ }
393
+ },
394
+ async (_, res) => {
395
+ res.send(true)
396
+ }
397
+ ))
398
+
399
+ // -------------------------------------------------------------------
400
+ // Reply Type Return Override
401
+ // -------------------------------------------------------------------
402
+
403
+ expectAssignable(server.withTypeProvider<JsonSchemaToTsProvider>().get<{Reply: boolean}>(
404
+ '/',
405
+ {
406
+ schema: {
407
+ response: {
408
+ 200: { type: 'string' },
409
+ 400: { type: 'number' },
410
+ 500: { type: 'object', properties: { error: { type: 'string' } } }
411
+ } as const
412
+ }
413
+ },
414
+ async (_, res) => {
415
+ return true
416
+ }
417
+ ))