fastify 4.13.0 → 4.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.
@@ -648,5 +648,7 @@ section.
648
648
  Reusable workflows for use in the Fastify plugin
649
649
  - [`fast-maker`](https://github.com/imjuni/fast-maker) route configuration
650
650
  generator by directory structure.
651
+ - [`fastify-flux`](https://github.com/Jnig/fastify-flux) Tool for building
652
+ Fastify APIs using decorators and convert Typescript interface to JSON Schema.
651
653
  - [`simple-tjscli`](https://github.com/imjuni/simple-tjscli) CLI tool to
652
654
  generate JSON Schema from TypeScript interfaces.
@@ -19,6 +19,7 @@ are Request/Reply hooks and application hooks:
19
19
  - [onSend](#onsend)
20
20
  - [onResponse](#onresponse)
21
21
  - [onTimeout](#ontimeout)
22
+ - [onRequestAbort](#onrequestabort)
22
23
  - [Manage Errors from a hook](#manage-errors-from-a-hook)
23
24
  - [Respond to a request from a hook](#respond-to-a-request-from-a-hook)
24
25
  - [Application Hooks](#application-hooks)
@@ -267,6 +268,26 @@ service (if the `connectionTimeout` property is set on the Fastify instance).
267
268
  The `onTimeout` hook is executed when a request is timed out and the HTTP socket
268
269
  has been hanged up. Therefore, you will not be able to send data to the client.
269
270
 
271
+ ### onRequestAbort
272
+
273
+ ```js
274
+ fastify.addHook('onRequestAbort', (request, reply, done) => {
275
+ // Some code
276
+ done()
277
+ })
278
+ ```
279
+ Or `async/await`:
280
+ ```js
281
+ fastify.addHook('onRequestAbort', async (request, reply) => {
282
+ // Some code
283
+ await asyncMethod()
284
+ })
285
+ ```
286
+ The `onRequestAbort` hook is executed when a client closes the connection before
287
+ the entire request has been processed. Therefore, you will not be able to send
288
+ data to the client.
289
+
290
+ **Notice:** client abort detection is not completely reliable. See: [`Detecting-When-Clients-Abort.md`](../Guides/Detecting-When-Clients-Abort.md)
270
291
 
271
292
  ### Manage Errors from a hook
272
293
  If you get an error during the execution of your hook, just pass it to `done()`
@@ -62,7 +62,7 @@ YAML workflow labels below:
62
62
  | OS | YAML Workflow Label | Package Manager | Node.js |
63
63
  |---------|------------------------|---------------------------|--------------|
64
64
  | Linux | `ubuntu-latest` | npm | 14,16,18 |
65
- | Linux | `ubuntu-18.04` | yarn,pnpm | 14,16,18 |
65
+ | Linux | `ubuntu-latest` | yarn,pnpm | 14,16,18 |
66
66
  | Windows | `windows-latest` | npm | 14,16,18 |
67
67
  | MacOS | `macos-latest` | npm | 14,16,18 |
68
68
 
@@ -382,7 +382,9 @@ fastify.addHook('onResponse', (req, reply, done) => {
382
382
  ```
383
383
 
384
384
  Please note that this setting will also disable an error log written by the
385
- default `onResponse` hook on reply callback errors.
385
+ default `onResponse` hook on reply callback errors. Other log messages
386
+ emitted by Fastify will stay enabled, like deprecation warnings and messages
387
+ emitted when requests are received while the server is closing.
386
388
 
387
389
  ### `serverFactory`
388
390
  <a id="custom-http-server"></a>
@@ -736,7 +738,8 @@ Fastify provides default error handlers for the most common use cases. It is
736
738
  possible to override one or more of those handlers with custom code using this
737
739
  option.
738
740
 
739
- *Note: Only `FST_ERR_BAD_URL` is implemented at the moment.*
741
+ *Note: Only `FST_ERR_BAD_URL` and `FST_ERR_ASYNC_CONSTRAINT` are implemented at
742
+ the moment.*
740
743
 
741
744
  ```js
742
745
  const fastify = require('fastify')({
package/fastify.d.ts CHANGED
@@ -3,16 +3,16 @@ import * as http2 from 'http2'
3
3
  import * as https from 'https'
4
4
  import { Socket } from 'net'
5
5
 
6
- import { Options as AjvOptions, ValidatorCompiler } from '@fastify/ajv-compiler'
6
+ import { Options as AjvOptions, ValidatorFactory } from '@fastify/ajv-compiler'
7
7
  import { FastifyError } from '@fastify/error'
8
- import { Options as FJSOptions, SerializerCompiler } from '@fastify/fast-json-stringify-compiler'
8
+ import { Options as FJSOptions, SerializerFactory } from '@fastify/fast-json-stringify-compiler'
9
9
  import { ConstraintStrategy, HTTPVersion } from 'find-my-way'
10
10
  import { Chain as LightMyRequestChain, InjectOptions, Response as LightMyRequestResponse, CallbackFunc as LightMyRequestCallback } from 'light-my-request'
11
11
 
12
12
  import { FastifyBodyParser, FastifyContentTypeParser, AddContentTypeParser, hasContentTypeParser, getDefaultJsonParser, ProtoAction, ConstructorAction } from './types/content-type-parser'
13
13
  import { FastifyContext, FastifyContextConfig } from './types/context'
14
14
  import { FastifyErrorCodes } from './types/errors'
15
- import { DoneFuncWithErrOrRes, HookHandlerDoneFunction, RequestPayload, onCloseAsyncHookHandler, onCloseHookHandler, onErrorAsyncHookHandler, onErrorHookHandler, onReadyAsyncHookHandler, onReadyHookHandler, onRegisterHookHandler, onRequestAsyncHookHandler, onRequestHookHandler, onResponseAsyncHookHandler, onResponseHookHandler, onRouteHookHandler, onSendAsyncHookHandler, onSendHookHandler, onTimeoutAsyncHookHandler, onTimeoutHookHandler, preHandlerAsyncHookHandler, preHandlerHookHandler, preParsingAsyncHookHandler, preParsingHookHandler, preSerializationAsyncHookHandler, preSerializationHookHandler, preValidationAsyncHookHandler, preValidationHookHandler } from './types/hooks'
15
+ import { DoneFuncWithErrOrRes, HookHandlerDoneFunction, RequestPayload, onCloseAsyncHookHandler, onCloseHookHandler, onErrorAsyncHookHandler, onErrorHookHandler, onReadyAsyncHookHandler, onReadyHookHandler, onRegisterHookHandler, onRequestAsyncHookHandler, onRequestHookHandler, onResponseAsyncHookHandler, onResponseHookHandler, onRouteHookHandler, onSendAsyncHookHandler, onSendHookHandler, onTimeoutAsyncHookHandler, onTimeoutHookHandler, preHandlerAsyncHookHandler, preHandlerHookHandler, preParsingAsyncHookHandler, preParsingHookHandler, preSerializationAsyncHookHandler, preSerializationHookHandler, preValidationAsyncHookHandler, preValidationHookHandler, onRequestAbortHookHandler, onRequestAbortAsyncHookHandler } from './types/hooks'
16
16
  import { FastifyListenOptions, FastifyInstance, PrintRoutesOptions } from './types/instance'
17
17
  import { FastifyBaseLogger, FastifyLoggerInstance, FastifyLoggerOptions, PinoLoggerOptions, FastifyLogFn, LogLevel } from './types/logger'
18
18
  import { FastifyPluginCallback, FastifyPluginAsync, FastifyPluginOptions, FastifyPlugin } from './types/plugin'
@@ -20,7 +20,7 @@ import { FastifyRegister, FastifyRegisterOptions, RegisterOptions } from './type
20
20
  import { FastifyReply } from './types/reply'
21
21
  import { FastifyRequest, RequestGenericInterface } from './types/request'
22
22
  import { RouteHandler, RouteHandlerMethod, RouteOptions, RouteShorthandMethod, RouteShorthandOptions, RouteShorthandOptionsWithHandler, RouteGenericInterface } from './types/route'
23
- import { FastifySchema, FastifySchemaCompiler, FastifySchemaValidationError } from './types/schema'
23
+ import { FastifySchema, FastifySchemaCompiler, SchemaErrorDataVar, SchemaErrorFormatter } from './types/schema'
24
24
  import { FastifyServerFactory, FastifyServerFactoryHandler } from './types/serverFactory'
25
25
  import { FastifyTypeProvider, FastifyTypeProviderDefault } from './types/type-provider'
26
26
  import { HTTPMethods, RawServerBase, RawRequestDefaultExpression, RawReplyDefaultExpression, RawServerDefault, ContextConfigDefault, RequestBodyDefault, RequestQuerystringDefault, RequestParamsDefault, RequestHeadersDefault } from './types/utils'
@@ -28,7 +28,7 @@ import { HTTPMethods, RawServerBase, RawRequestDefaultExpression, RawReplyDefaul
28
28
  declare module '@fastify/error' {
29
29
  interface FastifyError {
30
30
  validation?: fastify.ValidationResult[];
31
- validationContext?: 'body' | 'headers' | 'parameters' | 'querystring';
31
+ validationContext?: SchemaErrorDataVar;
32
32
  }
33
33
  }
34
34
 
@@ -134,8 +134,8 @@ declare namespace fastify {
134
134
  getSchemas(): Record<string, unknown>;
135
135
  };
136
136
  compilersFactory?: {
137
- buildValidator?: ValidatorCompiler;
138
- buildSerializer?: SerializerCompiler;
137
+ buildValidator?: ValidatorFactory;
138
+ buildSerializer?: SerializerFactory;
139
139
  };
140
140
  };
141
141
  return503OnClosing?: boolean,
@@ -149,7 +149,7 @@ declare namespace fastify {
149
149
  res: FastifyReply<RawServer, RawRequestDefaultExpression<RawServer>, RawReplyDefaultExpression<RawServer>, RequestGeneric, FastifyContextConfig, SchemaCompiler, TypeProvider>
150
150
  ) => void,
151
151
  rewriteUrl?: (req: RawRequestDefaultExpression<RawServer>) => string,
152
- schemaErrorFormatter?: (errors: FastifySchemaValidationError[], dataVar: string) => Error,
152
+ schemaErrorFormatter?: SchemaErrorFormatter,
153
153
  /**
154
154
  * listener to error events emitted by client connections
155
155
  */
@@ -179,7 +179,7 @@ declare namespace fastify {
179
179
  FastifyError, // '@fastify/error'
180
180
  FastifySchema, FastifySchemaCompiler, // './types/schema'
181
181
  HTTPMethods, RawServerBase, RawRequestDefaultExpression, RawReplyDefaultExpression, RawServerDefault, ContextConfigDefault, RequestBodyDefault, RequestQuerystringDefault, RequestParamsDefault, RequestHeadersDefault, // './types/utils'
182
- DoneFuncWithErrOrRes, HookHandlerDoneFunction, RequestPayload, onCloseAsyncHookHandler, onCloseHookHandler, onErrorAsyncHookHandler, onErrorHookHandler, onReadyAsyncHookHandler, onReadyHookHandler, onRegisterHookHandler, onRequestAsyncHookHandler, onRequestHookHandler, onResponseAsyncHookHandler, onResponseHookHandler, onRouteHookHandler, onSendAsyncHookHandler, onSendHookHandler, onTimeoutAsyncHookHandler, onTimeoutHookHandler, preHandlerAsyncHookHandler, preHandlerHookHandler, preParsingAsyncHookHandler, preParsingHookHandler, preSerializationAsyncHookHandler, preSerializationHookHandler, preValidationAsyncHookHandler, preValidationHookHandler, // './types/hooks'
182
+ DoneFuncWithErrOrRes, HookHandlerDoneFunction, RequestPayload, onCloseAsyncHookHandler, onCloseHookHandler, onErrorAsyncHookHandler, onErrorHookHandler, onReadyAsyncHookHandler, onReadyHookHandler, onRegisterHookHandler, onRequestAsyncHookHandler, onRequestHookHandler, onResponseAsyncHookHandler, onResponseHookHandler, onRouteHookHandler, onSendAsyncHookHandler, onSendHookHandler, onTimeoutAsyncHookHandler, onTimeoutHookHandler, preHandlerAsyncHookHandler, preHandlerHookHandler, preParsingAsyncHookHandler, preParsingHookHandler, preSerializationAsyncHookHandler, preSerializationHookHandler, preValidationAsyncHookHandler, preValidationHookHandler, onRequestAbortHookHandler, onRequestAbortAsyncHookHandler, // './types/hooks'
183
183
  FastifyServerFactory, FastifyServerFactoryHandler, // './types/serverFactory'
184
184
  FastifyTypeProvider, FastifyTypeProviderDefault, // './types/type-provider'
185
185
  FastifyErrorCodes, // './types/errors'
package/fastify.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const VERSION = '4.13.0'
3
+ const VERSION = '4.14.1'
4
4
 
5
5
  const Avvio = require('avvio')
6
6
  const http = require('http')
@@ -588,6 +588,10 @@ function fastify (options) {
588
588
  if (fn.constructor.name === 'AsyncFunction' && fn.length !== 0) {
589
589
  throw new errorCodes.FST_ERR_HOOK_INVALID_ASYNC_HANDLER()
590
590
  }
591
+ } else if (name === 'onRequestAbort') {
592
+ if (fn.constructor.name === 'AsyncFunction' && fn.length !== 1) {
593
+ throw new errorCodes.FST_ERR_HOOK_INVALID_ASYNC_HANDLER()
594
+ }
591
595
  } else {
592
596
  if (fn.constructor.name === 'AsyncFunction' && fn.length === 3) {
593
597
  throw new errorCodes.FST_ERR_HOOK_INVALID_ASYNC_HANDLER()
package/lib/context.js CHANGED
@@ -11,8 +11,8 @@ const {
11
11
  kLogLevel,
12
12
  kContentTypeParser,
13
13
  kRouteByFastify,
14
- kRequestValidateWeakMap,
15
- kReplySerializeWeakMap,
14
+ kRequestCacheValidateFns,
15
+ kReplyCacheSerializeFns,
16
16
  kPublicRouteContext
17
17
  } = require('./symbols.js')
18
18
 
@@ -48,6 +48,7 @@ function Context ({
48
48
  this.preHandler = null
49
49
  this.onResponse = null
50
50
  this.preSerialization = null
51
+ this.onRequestAbort = null
51
52
  this.config = config
52
53
  this.errorHandler = errorHandler || server[kErrorHandler]
53
54
  this._middie = null
@@ -67,8 +68,8 @@ function Context ({
67
68
  defaultSchemaErrorFormatter
68
69
  this[kRouteByFastify] = isFastify
69
70
 
70
- this[kRequestValidateWeakMap] = null
71
- this[kReplySerializeWeakMap] = null
71
+ this[kRequestCacheValidateFns] = null
72
+ this[kReplyCacheSerializeFns] = null
72
73
  this.validatorCompiler = validatorCompiler || null
73
74
  this.serializerCompiler = serializerCompiler || null
74
75
 
@@ -11,7 +11,8 @@ const {
11
11
  } = require('./symbols.js')
12
12
 
13
13
  const {
14
- FST_ERR_REP_INVALID_PAYLOAD_TYPE
14
+ FST_ERR_REP_INVALID_PAYLOAD_TYPE,
15
+ FST_ERR_FAILED_ERROR_SERIALIZATION
15
16
  } = require('./errors')
16
17
 
17
18
  const { getSchemaSerializer } = require('./schemas')
@@ -113,11 +114,7 @@ function fallbackErrorHandler (error, reply, cb) {
113
114
  // error is always FST_ERR_SCH_SERIALIZATION_BUILD because this is called from route/compileSchemasForSerialization
114
115
  reply.log.error({ err, statusCode: res.statusCode }, 'The serializer for the given status code failed')
115
116
  reply.code(500)
116
- payload = serializeError({
117
- error: statusCodes['500'],
118
- message: err.message,
119
- statusCode: 500
120
- })
117
+ payload = serializeError(new FST_ERR_FAILED_ERROR_SERIALIZATION(err.message, error.message))
121
118
  }
122
119
 
123
120
  if (typeof payload !== 'string' && !Buffer.isBuffer(payload)) {
@@ -2,15 +2,14 @@
2
2
  /* istanbul ignore file */
3
3
 
4
4
  'use strict'
5
-
6
5
 
7
6
 
8
7
  // eslint-disable-next-line
9
8
  const STR_ESCAPE = /[\u0000-\u001f\u0022\u005c\ud800-\udfff]|[\ud800-\udbff](?![\udc00-\udfff])|(?:[^\ud800-\udbff]|^)[\udc00-\udfff]/
10
9
 
11
10
  class Serializer {
12
- constructor (options = {}) {
13
- switch (options.rounding) {
11
+ constructor (options) {
12
+ switch (options && options.rounding) {
14
13
  case 'floor':
15
14
  this.parseInteger = Math.floor
16
15
  break
@@ -20,6 +19,7 @@ class Serializer {
20
19
  case 'round':
21
20
  this.parseInteger = Math.round
22
21
  break
22
+ case 'trunc':
23
23
  default:
24
24
  this.parseInteger = Math.trunc
25
25
  break
@@ -27,17 +27,28 @@ class Serializer {
27
27
  }
28
28
 
29
29
  asInteger (i) {
30
- if (typeof i === 'bigint') {
30
+ if (typeof i === 'number') {
31
+ if (i === Infinity || i === -Infinity) {
32
+ throw new Error(`The value "${i}" cannot be converted to an integer.`)
33
+ }
34
+ if (Number.isInteger(i)) {
35
+ return '' + i
36
+ }
37
+ if (Number.isNaN(i)) {
38
+ throw new Error(`The value "${i}" cannot be converted to an integer.`)
39
+ }
40
+ return this.parseInteger(i)
41
+ } else if (i === null) {
42
+ return '0'
43
+ } else if (typeof i === 'bigint') {
31
44
  return i.toString()
32
- } else if (Number.isInteger(i)) {
33
- return '' + i
34
45
  } else {
35
46
  /* eslint no-undef: "off" */
36
47
  const integer = this.parseInteger(i)
37
- if (Number.isNaN(integer) || !Number.isFinite(integer)) {
38
- throw new Error(`The value "${i}" cannot be converted to an integer.`)
39
- } else {
48
+ if (Number.isFinite(integer)) {
40
49
  return '' + integer
50
+ } else {
51
+ throw new Error(`The value "${i}" cannot be converted to an integer.`)
41
52
  }
42
53
  }
43
54
  }
@@ -91,23 +102,24 @@ class Serializer {
91
102
  }
92
103
 
93
104
  asString (str) {
94
- const quotes = '"'
95
- if (str instanceof Date) {
96
- return quotes + str.toISOString() + quotes
97
- } else if (str === null) {
98
- return quotes + quotes
99
- } else if (str instanceof RegExp) {
100
- str = str.source
101
- } else if (typeof str !== 'string') {
102
- str = str.toString()
105
+ if (typeof str !== 'string') {
106
+ if (str === null) {
107
+ return '""'
108
+ }
109
+ if (str instanceof Date) {
110
+ return '"' + str.toISOString() + '"'
111
+ }
112
+ if (str instanceof RegExp) {
113
+ str = str.source
114
+ } else {
115
+ str = str.toString()
116
+ }
103
117
  }
104
118
 
105
119
  // Fast escape chars check
106
120
  if (!STR_ESCAPE.test(str)) {
107
- return quotes + str + quotes
108
- }
109
-
110
- if (str.length < 42) {
121
+ return '"' + str + '"'
122
+ } else if (str.length < 42) {
111
123
  return this.asStringSmall(str)
112
124
  } else {
113
125
  return JSON.stringify(str)
@@ -151,81 +163,50 @@ class Serializer {
151
163
  }
152
164
 
153
165
 
154
-
155
- const serializer = new Serializer({"mode":"standalone"})
166
+ const serializer = new Serializer()
156
167
 
157
168
 
158
169
 
159
- function main (input) {
160
- let json = ''
161
- json += anonymous0(input)
162
- return json
163
- }
164
170
 
165
171
  function anonymous0 (input) {
166
172
  // #
167
173
 
168
- var obj = (input && typeof input.toJSON === 'function')
174
+ const obj = (input && typeof input.toJSON === 'function')
169
175
  ? input.toJSON()
170
176
  : input
171
177
 
172
- var json = '{'
173
- var addComma = false
178
+ let json = '{'
179
+ let addComma = false
174
180
 
175
181
  if (obj["statusCode"] !== undefined) {
176
-
177
- if (addComma) {
178
- json += ','
179
- } else {
180
- addComma = true
181
- }
182
-
183
- json += "\"statusCode\"" + ':'
182
+ !addComma && (addComma = true) || (json += ',')
183
+ json += "\"statusCode\":"
184
184
  json += serializer.asNumber(obj["statusCode"])
185
185
  }
186
186
 
187
187
  if (obj["code"] !== undefined) {
188
-
189
- if (addComma) {
190
- json += ','
191
- } else {
192
- addComma = true
193
- }
194
-
195
- json += "\"code\"" + ':'
188
+ !addComma && (addComma = true) || (json += ',')
189
+ json += "\"code\":"
196
190
  json += serializer.asString(obj["code"])
197
191
  }
198
192
 
199
193
  if (obj["error"] !== undefined) {
200
-
201
- if (addComma) {
202
- json += ','
203
- } else {
204
- addComma = true
205
- }
206
-
207
- json += "\"error\"" + ':'
194
+ !addComma && (addComma = true) || (json += ',')
195
+ json += "\"error\":"
208
196
  json += serializer.asString(obj["error"])
209
197
  }
210
198
 
211
199
  if (obj["message"] !== undefined) {
212
-
213
- if (addComma) {
214
- json += ','
215
- } else {
216
- addComma = true
217
- }
218
-
219
- json += "\"message\"" + ':'
200
+ !addComma && (addComma = true) || (json += ',')
201
+ json += "\"message\":"
220
202
  json += serializer.asString(obj["message"])
221
203
  }
222
204
 
223
- json += '}'
224
- return json
205
+ return json + '}'
225
206
  }
226
207
 
208
+ const main = anonymous0
209
+
227
210
 
228
-
229
211
 
230
212
  module.exports = main
231
-
package/lib/errors.js CHANGED
@@ -214,6 +214,10 @@ const codes = {
214
214
  'FST_ERR_BAD_TRAILER_VALUE',
215
215
  "Called reply.trailer('%s', fn) with an invalid type: %s. Expected a function."
216
216
  ),
217
+ FST_ERR_FAILED_ERROR_SERIALIZATION: createError(
218
+ 'FST_ERR_FAILED_ERROR_SERIALIZATION',
219
+ 'Failed to serialize an error. Error: %s. Original error: %s'
220
+ ),
217
221
  FST_ERR_MISSING_SERIALIZATION_FN: createError(
218
222
  'FST_ERR_MISSING_SERIALIZATION_FN',
219
223
  'Missing serialization function. Key "%s"'
package/lib/hooks.js CHANGED
@@ -15,7 +15,8 @@ const lifecycleHooks = [
15
15
  'preHandler',
16
16
  'onSend',
17
17
  'onResponse',
18
- 'onError'
18
+ 'onError',
19
+ 'onRequestAbort'
19
20
  ]
20
21
  const supportedHooks = lifecycleHooks.concat(applicationHooks)
21
22
  const {
@@ -46,6 +47,7 @@ function Hooks () {
46
47
  this.onRegister = []
47
48
  this.onReady = []
48
49
  this.onTimeout = []
50
+ this.onRequestAbort = []
49
51
  }
50
52
 
51
53
  Hooks.prototype.validate = function (hook, fn) {
@@ -74,6 +76,7 @@ function buildHooks (h) {
74
76
  hooks.onRoute = h.onRoute.slice()
75
77
  hooks.onRegister = h.onRegister.slice()
76
78
  hooks.onTimeout = h.onTimeout.slice()
79
+ hooks.onRequestAbort = h.onRequestAbort.slice()
77
80
  hooks.onReady = []
78
81
  return hooks
79
82
  }
@@ -246,6 +249,42 @@ function onSendHookRunner (functions, request, reply, payload, cb) {
246
249
  next()
247
250
  }
248
251
 
252
+ function onRequestAbortHookRunner (functions, runner, request, cb) {
253
+ let i = 0
254
+
255
+ function next (err) {
256
+ if (err || i === functions.length) {
257
+ cb(err, request)
258
+ return
259
+ }
260
+
261
+ let result
262
+ try {
263
+ result = runner(functions[i++], request, next)
264
+ } catch (error) {
265
+ next(error)
266
+ return
267
+ }
268
+ if (result && typeof result.then === 'function') {
269
+ result.then(handleResolve, handleReject)
270
+ }
271
+ }
272
+
273
+ function handleResolve () {
274
+ next()
275
+ }
276
+
277
+ function handleReject (err) {
278
+ if (!err) {
279
+ err = new FST_ERR_SEND_UNDEFINED_ERR()
280
+ }
281
+
282
+ cb(err, request)
283
+ }
284
+
285
+ next()
286
+ }
287
+
249
288
  function hookIterator (fn, request, reply, next) {
250
289
  if (reply.sent === true) return undefined
251
290
  return fn(request, reply, next)
@@ -256,6 +295,7 @@ module.exports = {
256
295
  buildHooks,
257
296
  hookRunner,
258
297
  onSendHookRunner,
298
+ onRequestAbortHookRunner,
259
299
  hookIterator,
260
300
  hookRunnerApplication,
261
301
  lifecycleHooks,
package/lib/reply.js CHANGED
@@ -18,7 +18,7 @@ const {
18
18
  kReplyNextErrorHandler,
19
19
  kDisableRequestLogging,
20
20
  kSchemaResponse,
21
- kReplySerializeWeakMap,
21
+ kReplyCacheSerializeFns,
22
22
  kSchemaController,
23
23
  kOptions,
24
24
  kRouteContext
@@ -323,7 +323,7 @@ Reply.prototype.getSerializationFunction = function (schemaOrStatus, contentType
323
323
  serialize = this[kRouteContext][kSchemaResponse]?.[schemaOrStatus]
324
324
  }
325
325
  } else if (typeof schemaOrStatus === 'object') {
326
- serialize = this[kRouteContext][kReplySerializeWeakMap]?.get(schemaOrStatus)
326
+ serialize = this[kRouteContext][kReplyCacheSerializeFns]?.get(schemaOrStatus)
327
327
  }
328
328
 
329
329
  return serialize
@@ -334,8 +334,8 @@ Reply.prototype.compileSerializationSchema = function (schema, httpStatus = null
334
334
  const { method, url } = request
335
335
 
336
336
  // Check if serialize function already compiled
337
- if (this[kRouteContext][kReplySerializeWeakMap]?.has(schema)) {
338
- return this[kRouteContext][kReplySerializeWeakMap].get(schema)
337
+ if (this[kRouteContext][kReplyCacheSerializeFns]?.has(schema)) {
338
+ return this[kRouteContext][kReplyCacheSerializeFns].get(schema)
339
339
  }
340
340
 
341
341
  const serializerCompiler = this[kRouteContext].serializerCompiler ||
@@ -360,11 +360,11 @@ Reply.prototype.compileSerializationSchema = function (schema, httpStatus = null
360
360
  // if it is not used
361
361
  // TODO: Explore a central cache for all the schemas shared across
362
362
  // encapsulated contexts
363
- if (this[kRouteContext][kReplySerializeWeakMap] == null) {
364
- this[kRouteContext][kReplySerializeWeakMap] = new WeakMap()
363
+ if (this[kRouteContext][kReplyCacheSerializeFns] == null) {
364
+ this[kRouteContext][kReplyCacheSerializeFns] = new WeakMap()
365
365
  }
366
366
 
367
- this[kRouteContext][kReplySerializeWeakMap].set(schema, serializeFn)
367
+ this[kRouteContext][kReplyCacheSerializeFns].set(schema, serializeFn)
368
368
 
369
369
  return serializeFn
370
370
  }
@@ -393,8 +393,8 @@ Reply.prototype.serializeInput = function (input, schema, httpStatus, contentTyp
393
393
  }
394
394
  } else {
395
395
  // Check if serialize function already compiled
396
- if (this[kRouteContext][kReplySerializeWeakMap]?.has(schema)) {
397
- serialize = this[kRouteContext][kReplySerializeWeakMap].get(schema)
396
+ if (this[kRouteContext][kReplyCacheSerializeFns]?.has(schema)) {
397
+ serialize = this[kRouteContext][kReplyCacheSerializeFns].get(schema)
398
398
  } else {
399
399
  serialize = this.compileSerializationSchema(schema, httpStatus, contentType)
400
400
  }
package/lib/request.js CHANGED
@@ -11,7 +11,7 @@ const {
11
11
  kSchemaQuerystring,
12
12
  kSchemaController,
13
13
  kOptions,
14
- kRequestValidateWeakMap,
14
+ kRequestCacheValidateFns,
15
15
  kRouteContext,
16
16
  kPublicRouteContext
17
17
  } = require('./symbols')
@@ -254,7 +254,7 @@ Object.defineProperties(Request.prototype, {
254
254
  const symbol = HTTP_PART_SYMBOL_MAP[httpPartOrSchema]
255
255
  return this[kRouteContext][symbol]
256
256
  } else if (typeof httpPartOrSchema === 'object') {
257
- return this[kRouteContext][kRequestValidateWeakMap]?.get(httpPartOrSchema)
257
+ return this[kRouteContext][kRequestCacheValidateFns]?.get(httpPartOrSchema)
258
258
  }
259
259
  }
260
260
  },
@@ -262,8 +262,8 @@ Object.defineProperties(Request.prototype, {
262
262
  value: function (schema, httpPart = null) {
263
263
  const { method, url } = this
264
264
 
265
- if (this[kRouteContext][kRequestValidateWeakMap]?.has(schema)) {
266
- return this[kRouteContext][kRequestValidateWeakMap].get(schema)
265
+ if (this[kRouteContext][kRequestCacheValidateFns]?.has(schema)) {
266
+ return this[kRouteContext][kRequestCacheValidateFns].get(schema)
267
267
  }
268
268
 
269
269
  const validatorCompiler = this[kRouteContext].validatorCompiler ||
@@ -287,11 +287,11 @@ Object.defineProperties(Request.prototype, {
287
287
  // if it is not used
288
288
  // TODO: Explore a central cache for all the schemas shared across
289
289
  // encapsulated contexts
290
- if (this[kRouteContext][kRequestValidateWeakMap] == null) {
291
- this[kRouteContext][kRequestValidateWeakMap] = new WeakMap()
290
+ if (this[kRouteContext][kRequestCacheValidateFns] == null) {
291
+ this[kRouteContext][kRequestCacheValidateFns] = new WeakMap()
292
292
  }
293
293
 
294
- this[kRouteContext][kRequestValidateWeakMap].set(schema, validateFn)
294
+ this[kRouteContext][kRequestCacheValidateFns].set(schema, validateFn)
295
295
 
296
296
  return validateFn
297
297
  }
@@ -317,8 +317,8 @@ Object.defineProperties(Request.prototype, {
317
317
  }
318
318
 
319
319
  if (validate == null) {
320
- if (this[kRouteContext][kRequestValidateWeakMap]?.has(schema)) {
321
- validate = this[kRouteContext][kRequestValidateWeakMap].get(schema)
320
+ if (this[kRouteContext][kRequestCacheValidateFns]?.has(schema)) {
321
+ validate = this[kRouteContext][kRequestCacheValidateFns].get(schema)
322
322
  } else {
323
323
  // We proceed to compile if there's no validate function yet
324
324
  validate = this.compileValidationSchema(schema, httpPart)