@webiny/handler 0.0.0-unstable.d7f521b032 → 0.0.0-unstable.dbdf5d6258

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 (89) hide show
  1. package/Context.d.ts +18 -10
  2. package/Context.js +17 -22
  3. package/Context.js.map +1 -1
  4. package/PreHandler/IPreHandler.d.ts +9 -0
  5. package/PreHandler/IPreHandler.js +7 -0
  6. package/PreHandler/IPreHandler.js.map +1 -0
  7. package/PreHandler/IfNotOptionsRequest.d.ts +9 -0
  8. package/PreHandler/IfNotOptionsRequest.js +21 -0
  9. package/PreHandler/IfNotOptionsRequest.js.map +1 -0
  10. package/PreHandler/IfOptionsRequest.d.ts +9 -0
  11. package/PreHandler/IfOptionsRequest.js +21 -0
  12. package/PreHandler/IfOptionsRequest.js.map +1 -0
  13. package/PreHandler/PreHandler.d.ts +9 -0
  14. package/PreHandler/PreHandler.js +17 -0
  15. package/PreHandler/PreHandler.js.map +1 -0
  16. package/PreHandler/ProcessBeforeHandlerPlugins.d.ts +10 -0
  17. package/PreHandler/ProcessBeforeHandlerPlugins.js +24 -0
  18. package/PreHandler/ProcessBeforeHandlerPlugins.js.map +1 -0
  19. package/PreHandler/ProcessContextPlugins.d.ts +10 -0
  20. package/PreHandler/ProcessContextPlugins.js +24 -0
  21. package/PreHandler/ProcessContextPlugins.js.map +1 -0
  22. package/PreHandler/ProcessHandlerOnRequestPlugins.d.ts +10 -0
  23. package/PreHandler/ProcessHandlerOnRequestPlugins.js +26 -0
  24. package/PreHandler/ProcessHandlerOnRequestPlugins.js.map +1 -0
  25. package/PreHandler/SendEarlyOptionsResponse.d.ts +9 -0
  26. package/PreHandler/SendEarlyOptionsResponse.js +31 -0
  27. package/PreHandler/SendEarlyOptionsResponse.js.map +1 -0
  28. package/PreHandler/SetDefaultHeaders.d.ts +9 -0
  29. package/PreHandler/SetDefaultHeaders.js +57 -0
  30. package/PreHandler/SetDefaultHeaders.js.map +1 -0
  31. package/README.md +10 -14
  32. package/ResponseHeaders.d.ts +24 -0
  33. package/ResponseHeaders.js +39 -0
  34. package/ResponseHeaders.js.map +1 -0
  35. package/abstractions/Reply.d.ts +5 -0
  36. package/abstractions/Reply.js +4 -0
  37. package/abstractions/Reply.js.map +1 -0
  38. package/abstractions/Request.d.ts +5 -0
  39. package/abstractions/Request.js +4 -0
  40. package/abstractions/Request.js.map +1 -0
  41. package/fastify.d.ts +8 -5
  42. package/fastify.js +238 -278
  43. package/fastify.js.map +1 -1
  44. package/index.d.ts +17 -10
  45. package/index.js +20 -135
  46. package/index.js.map +1 -1
  47. package/package.json +16 -26
  48. package/plugins/BeforeHandlerPlugin.d.ts +1 -1
  49. package/plugins/BeforeHandlerPlugin.js +5 -24
  50. package/plugins/BeforeHandlerPlugin.js.map +1 -1
  51. package/plugins/EventPlugin.d.ts +3 -3
  52. package/plugins/EventPlugin.js +5 -22
  53. package/plugins/EventPlugin.js.map +1 -1
  54. package/plugins/HandlerErrorPlugin.d.ts +6 -3
  55. package/plugins/HandlerErrorPlugin.js +5 -23
  56. package/plugins/HandlerErrorPlugin.js.map +1 -1
  57. package/plugins/HandlerOnRequestPlugin.d.ts +9 -8
  58. package/plugins/HandlerOnRequestPlugin.js +13 -23
  59. package/plugins/HandlerOnRequestPlugin.js.map +1 -1
  60. package/plugins/HandlerResultPlugin.d.ts +1 -1
  61. package/plugins/HandlerResultPlugin.js +5 -23
  62. package/plugins/HandlerResultPlugin.js.map +1 -1
  63. package/plugins/ModifyFastifyPlugin.d.ts +2 -2
  64. package/plugins/ModifyFastifyPlugin.js +5 -23
  65. package/plugins/ModifyFastifyPlugin.js.map +1 -1
  66. package/plugins/ModifyResponseHeadersPlugin.d.ts +14 -0
  67. package/plugins/ModifyResponseHeadersPlugin.js +16 -0
  68. package/plugins/ModifyResponseHeadersPlugin.js.map +1 -0
  69. package/plugins/OnRequestResponseSendPlugin.d.ts +26 -0
  70. package/plugins/OnRequestResponseSendPlugin.js +31 -0
  71. package/plugins/OnRequestResponseSendPlugin.js.map +1 -0
  72. package/plugins/OnRequestTimeoutPlugin.d.ts +12 -0
  73. package/plugins/OnRequestTimeoutPlugin.js +16 -0
  74. package/plugins/OnRequestTimeoutPlugin.js.map +1 -0
  75. package/plugins/RoutePlugin.d.ts +2 -2
  76. package/plugins/RoutePlugin.js +5 -22
  77. package/plugins/RoutePlugin.js.map +1 -1
  78. package/stringifyError.d.ts +5 -0
  79. package/stringifyError.js +20 -0
  80. package/stringifyError.js.map +1 -0
  81. package/suppressPunycodeWarnings.d.ts +1 -0
  82. package/suppressPunycodeWarnings.js +10 -0
  83. package/suppressPunycodeWarnings.js.map +1 -0
  84. package/types.d.ts +10 -13
  85. package/types.js +2 -18
  86. package/types.js.map +1 -1
  87. package/middleware.d.ts +0 -4
  88. package/middleware.js +0 -51
  89. package/middleware.js.map +0 -1
package/fastify.js CHANGED
@@ -1,102 +1,48 @@
1
- "use strict";
2
-
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
-
5
- Object.defineProperty(exports, "__esModule", {
6
- value: true
7
- });
8
- exports.createHandler = void 0;
9
-
10
- var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
11
-
12
- var _fastify = _interopRequireDefault(require("fastify"));
13
-
14
- var _utils = require("@webiny/utils");
15
-
16
- var _Context = require("./Context");
17
-
18
- var _error = _interopRequireDefault(require("@webiny/error"));
19
-
20
- var _RoutePlugin = require("./plugins/RoutePlugin");
21
-
22
- var _handlerClient = require("@webiny/handler-client");
23
-
24
- var _cookie = _interopRequireDefault(require("@fastify/cookie"));
25
-
26
- var _compress = _interopRequireDefault(require("@fastify/compress"));
27
-
28
- var _middleware = require("./middleware");
29
-
30
- var _api = require("@webiny/api");
31
-
32
- var _BeforeHandlerPlugin = require("./plugins/BeforeHandlerPlugin");
33
-
34
- var _HandlerResultPlugin = require("./plugins/HandlerResultPlugin");
35
-
36
- var _HandlerErrorPlugin = require("./plugins/HandlerErrorPlugin");
37
-
38
- var _ModifyFastifyPlugin = require("./plugins/ModifyFastifyPlugin");
39
-
40
- var _HandlerOnRequestPlugin = require("./plugins/HandlerOnRequestPlugin");
41
-
42
- const DEFAULT_HEADERS = (0, _objectSpread2.default)({
43
- "Cache-Control": "no-store",
44
- "Content-Type": "application/json; charset=utf-8",
45
- "Access-Control-Allow-Origin": "*",
46
- "Access-Control-Allow-Headers": "*",
47
- "Access-Control-Allow-Methods": "OPTIONS,POST,GET,DELETE,PUT,PATCH"
48
- }, (0, _utils.getWebinyVersionHeaders)());
49
-
50
- const getDefaultHeaders = routes => {
51
- /**
52
- * If we are accepting all headers, just output that one.
53
- */
54
- const keys = Object.keys(routes);
55
- const all = keys.every(key => routes[key].length > 0);
56
-
57
- if (all) {
58
- return (0, _objectSpread2.default)((0, _objectSpread2.default)({}, DEFAULT_HEADERS), {}, {
59
- "Access-Control-Allow-Methods": "*"
60
- });
61
- }
62
-
63
- return (0, _objectSpread2.default)((0, _objectSpread2.default)({}, DEFAULT_HEADERS), {}, {
64
- "Access-Control-Allow-Methods": keys.filter(type => {
65
- if (!routes[type] || Array.isArray(routes[type]) === false) {
66
- return false;
67
- }
68
-
69
- return routes[type].length > 0;
70
- }).sort().join(",")
1
+ import { PluginsContainer } from "@webiny/plugins/types.js";
2
+ import fastify from "fastify";
3
+ import { middleware } from "@webiny/utils";
4
+ import { Context } from "./Context.js";
5
+ import WebinyError from "@webiny/error";
6
+ import { RoutePlugin } from "./plugins/RoutePlugin.js";
7
+ import { createHandlerClient } from "@webiny/handler-client";
8
+ import fastifyCookie from "@fastify/cookie";
9
+ import fastifyCompress from "@fastify/compress";
10
+ import { ContextPlugin } from "@webiny/api";
11
+ import { BeforeHandlerPlugin } from "./plugins/BeforeHandlerPlugin.js";
12
+ import { HandlerResultPlugin } from "./plugins/HandlerResultPlugin.js";
13
+ import { HandlerErrorPlugin } from "./plugins/HandlerErrorPlugin.js";
14
+ import { ModifyFastifyPlugin } from "./plugins/ModifyFastifyPlugin.js";
15
+ import { HandlerOnRequestPlugin } from "./plugins/HandlerOnRequestPlugin.js";
16
+ import { ResponseHeaders } from "./ResponseHeaders.js";
17
+ import { ModifyResponseHeadersPlugin } from "./plugins/ModifyResponseHeadersPlugin.js";
18
+ import { SetDefaultHeaders } from "./PreHandler/SetDefaultHeaders.js";
19
+ import { PreHandler } from "./PreHandler/PreHandler.js";
20
+ import { stringifyError } from "./stringifyError.js";
21
+ import { ProcessHandlerOnRequestPlugins } from "./PreHandler/ProcessHandlerOnRequestPlugins.js";
22
+ import { ProcessContextPlugins } from "./PreHandler/ProcessContextPlugins.js";
23
+ import { IfNotOptionsRequest } from "./PreHandler/IfNotOptionsRequest.js";
24
+ import { ProcessBeforeHandlerPlugins } from "./PreHandler/ProcessBeforeHandlerPlugins.js";
25
+ import { IfOptionsRequest } from "./PreHandler/IfOptionsRequest.js";
26
+ import { SendEarlyOptionsResponse } from "./PreHandler/SendEarlyOptionsResponse.js";
27
+ import { OnRequestTimeoutPlugin } from "./plugins/OnRequestTimeoutPlugin.js";
28
+ import { OnRequestResponseSendPlugin } from "./plugins/OnRequestResponseSendPlugin.js";
29
+ import { Request } from "./abstractions/Request.js";
30
+ import { Reply } from "./abstractions/Reply.js";
31
+ const modifyResponseHeaders = (app, request, reply) => {
32
+ const modifyHeaders = app.webiny.plugins.byType(ModifyResponseHeadersPlugin.type);
33
+ const replyHeaders = reply.getHeaders();
34
+ const headers = ResponseHeaders.create(replyHeaders);
35
+ modifyHeaders.forEach(plugin => {
36
+ plugin.modify(request, headers);
71
37
  });
72
- };
73
-
74
- const stringifyError = error => {
75
- var _error$constructor;
76
38
 
77
- const {
78
- name,
79
- message,
80
- code,
81
- stack,
82
- data
83
- } = error;
84
- return JSON.stringify((0, _objectSpread2.default)((0, _objectSpread2.default)({}, error), {}, {
85
- constructorName: ((_error$constructor = error.constructor) === null || _error$constructor === void 0 ? void 0 : _error$constructor.name) || "UnknownError",
86
- name: name || "No error name",
87
- message: message || "No error message",
88
- code: code || "NO_CODE",
89
- data,
90
- stack: process.env.DEBUG === "true" ? stack : "Turn on the debug flag to see the stack."
91
- }));
39
+ // Exclude 'set-cookie' header to avoid duplication.
40
+ // Cookies are managed by @fastify/cookie and calling reply.headers() with 'set-cookie' duplicates them.
41
+ const headersToSet = headers.getHeaders();
42
+ delete headersToSet["set-cookie"];
43
+ reply.headers(headersToSet);
92
44
  };
93
-
94
- const OPTIONS_HEADERS = {
95
- "Access-Control-Max-Age": "86400",
96
- "Cache-Control": "public, max-age=86400"
97
- };
98
-
99
- const createHandler = params => {
45
+ export const createHandler = params => {
100
46
  const definedRoutes = {
101
47
  POST: [],
102
48
  GET: [],
@@ -113,93 +59,89 @@ const createHandler = params => {
113
59
  PROPPATCH: [],
114
60
  SEARCH: [],
115
61
  TRACE: [],
116
- UNLOCK: []
62
+ UNLOCK: [],
63
+ REPORT: [],
64
+ MKCALENDAR: []
117
65
  };
118
-
119
66
  const throwOnDefinedRoute = (type, path, options) => {
120
67
  if (type === "ALL") {
121
- const all = Object.keys(definedRoutes).find(key => {
68
+ const all = Object.keys(definedRoutes).find(k => {
69
+ const key = k.toUpperCase();
122
70
  const routes = definedRoutes[key];
123
71
  return routes.includes(path);
124
72
  });
125
-
126
73
  if (!all) {
127
74
  return;
128
75
  }
129
-
130
- console.log(`Error while registering onAll route. One of the routes is already defined.`);
131
- console.log(JSON.stringify(all));
132
- throw new _error.default(`You cannot override a route with onAll() method, please remove unnecessary route from the system.`, "OVERRIDE_ROUTE_ERROR", {
76
+ console.error(`Error while registering onAll route. One of the routes is already defined.`);
77
+ console.error(JSON.stringify(all));
78
+ throw new WebinyError(`You cannot override a route with onAll() method, please remove unnecessary route from the system.`, "OVERRIDE_ROUTE_ERROR", {
133
79
  type,
134
80
  path
135
81
  });
136
82
  } else if (definedRoutes[type].includes(path) === false) {
137
83
  return;
138
- } else if ((options === null || options === void 0 ? void 0 : options.override) === true) {
84
+ } else if (options?.override === true) {
139
85
  return;
140
86
  }
141
-
142
- console.log(`Error while trying to override route: [${type}] ${path}`);
143
- throw new _error.default(`When you are trying to override existing route, you must send "override" parameter when adding that route.`, "OVERRIDE_ROUTE_ERROR", {
87
+ console.error(`Error while trying to override route: [${type}] ${path}`);
88
+ throw new WebinyError(`When you are trying to override existing route, you must send "override" parameter when adding that route.`, "OVERRIDE_ROUTE_ERROR", {
144
89
  type,
145
90
  path
146
91
  });
147
92
  };
148
-
149
- const addDefinedRoute = (type, path) => {
93
+ const addDefinedRoute = (input, path) => {
94
+ const type = input.toUpperCase();
150
95
  if (!definedRoutes[type]) {
151
96
  return;
152
97
  } else if (definedRoutes[type].includes(path)) {
153
98
  return;
154
99
  }
155
-
156
100
  definedRoutes[type].push(path);
157
101
  };
102
+
158
103
  /**
159
104
  * We must attach the server to our internal context if we want to have it accessible.
160
105
  */
106
+ const app = fastify({
107
+ bodyLimit: 536870912,
108
+ // 512MB
109
+ disableRequestLogging: true,
110
+ allowErrorHandlerOverride: true,
111
+ ...(params.options || {})
112
+ });
161
113
 
162
-
163
- const app = (0, _fastify.default)((0, _objectSpread2.default)({}, params.options || {}));
164
114
  /**
165
- * We need to register routes in our system so we can output headers later on and dissallow overriding routes.
115
+ * We need to register routes in our system to output headers later on, and disallow route overriding.
166
116
  */
167
-
168
117
  app.addHook("onRoute", route => {
169
118
  const method = route.method;
170
-
171
119
  if (Array.isArray(method)) {
172
120
  for (const m of method) {
173
121
  addDefinedRoute(m, route.path);
174
122
  }
175
-
176
123
  return;
177
124
  }
178
-
179
125
  addDefinedRoute(method, route.path);
180
126
  });
181
127
  /**
182
128
  * ############################
183
129
  * Register the Fastify plugins.
184
130
  */
185
-
186
131
  /**
187
132
  * Package @fastify/cookie
188
133
  *
189
134
  * https://github.com/fastify/fastify-cookie
190
135
  */
191
-
192
- app.register(_cookie.default, {
136
+ app.register(fastifyCookie, {
193
137
  parseOptions: {} // options for parsing cookies
194
-
195
138
  });
196
139
  /**
197
140
  * Package @fastify/compress
198
141
  *
199
142
  * https://github.com/fastify/fastify-compress
200
143
  */
201
-
202
- app.register(_compress.default, {
144
+ app.register(fastifyCompress, {
203
145
  global: true,
204
146
  threshold: 1024,
205
147
  onUnsupportedEncoding: (encoding, _, reply) => {
@@ -211,7 +153,6 @@ const createHandler = params => {
211
153
  /**
212
154
  * Route helpers - mostly for users.
213
155
  */
214
-
215
156
  const routes = {
216
157
  defined: definedRoutes,
217
158
  onPost: (path, handler, options) => {
@@ -248,178 +189,133 @@ const createHandler = params => {
248
189
  }
249
190
  };
250
191
  let context;
251
-
192
+ const plugins = new PluginsContainer([
193
+ /**
194
+ * We must have handlerClient by default.
195
+ * And it must be one of the first context plugins applied.
196
+ */
197
+ createHandlerClient()]);
198
+ plugins.merge(params.plugins || []);
252
199
  try {
253
- context = new _Context.Context({
254
- plugins: [
200
+ context = new Context({
201
+ plugins,
255
202
  /**
256
- * We must have handlerClient by default.
257
- * And it must be one of the first context plugins applied.
258
- */
259
- (0, _handlerClient.createHandlerClient)(), ...(params.plugins || [])],
260
-
261
- /**
262
- * Inserted via webpack on build time.
203
+ * Inserted via webpack at build time.
263
204
  */
264
205
  WEBINY_VERSION: process.env.WEBINY_VERSION,
265
- server: app,
266
206
  routes
267
207
  });
268
208
  } catch (ex) {
269
- console.log(`Error while constructing the Context.`);
270
- console.log(stringifyError(ex));
209
+ console.error(`Error while constructing the Context.`);
210
+ console.error(stringifyError(ex));
271
211
  throw ex;
272
212
  }
213
+
273
214
  /**
274
215
  * We are attaching our custom context to webiny variable on the fastify app, so it is accessible everywhere.
275
216
  */
276
-
277
-
278
217
  app.decorate("webiny", context);
279
- /**
280
- * We have few types of triggers:
281
- * * Events - EventPlugin
282
- * * Routes - RoutePlugin
283
- *
284
- * Routes are registered in fastify but events must be handled in package which implements cloud specific methods.
285
- */
286
218
 
287
- const routePlugins = app.webiny.plugins.byType(_RoutePlugin.RoutePlugin.type);
288
219
  /**
289
- * Add routes to the system.
220
+ * To prevent Unsupported Media Type errors on OPTIONS requests with a body,
221
+ * we need to have a custom parser
290
222
  */
291
-
292
- let routePluginName;
293
-
294
- try {
295
- for (const plugin of routePlugins) {
296
- routePluginName = plugin.name;
297
- plugin.cb((0, _objectSpread2.default)((0, _objectSpread2.default)({}, app.webiny.routes), {}, {
298
- context: app.webiny
299
- }));
300
- }
301
- } catch (ex) {
302
- console.log(`Error while running the "RoutePlugin" ${routePluginName ? `(${routePluginName})` : ""} plugin in the beginning of the "createHandler" callable.`);
303
- console.log(stringifyError(ex));
304
- throw ex;
305
- }
306
- /**
307
- * On every request we add default headers, which can be changed later.
308
- * Also, if it is an options request, we skip everything after this hook and output options headers.
309
- */
310
-
311
-
312
- app.addHook("onRequest", async (request, reply) => {
313
- /**
314
- * Our default headers are always set. Users can override them.
315
- */
316
- const defaultHeaders = getDefaultHeaders(definedRoutes);
317
- reply.headers(defaultHeaders);
318
- /**
319
- * Users can define their own custom handlers for the onRequest event - so let's run them first.
320
- */
321
-
322
- const plugins = app.webiny.plugins.byType(_HandlerOnRequestPlugin.HandlerOnRequestPlugin.type);
323
- let name;
324
-
325
- try {
326
- for (const plugin of plugins) {
327
- name = plugin.name;
328
- const result = await plugin.exec(request, reply);
329
-
330
- if (result === false) {
331
- return;
332
- }
333
- }
334
- } catch (ex) {
335
- console.log(`Error while running the "HandlerOnRequestPlugin" ${name ? `(${name})` : ""} plugin in the onRequest hook.`);
336
- console.log(stringifyError(ex));
337
- throw ex;
338
- }
339
- /**
340
- * When we receive the OPTIONS request, we end it before it goes any further as there is no need for anything to run after this - at least for our use cases.
341
- *
342
- * Users can prevent this by creating their own HandlerOnRequestPlugin and returning false as the result of the callable.
343
- */
344
-
345
-
346
- if (request.method !== "OPTIONS") {
223
+ app.addContentTypeParser("application/json", {
224
+ parseAs: "string",
225
+ bodyLimit: 1024 * 1024
226
+ }, (req, body, done) => {
227
+ if (req.method === "OPTIONS") {
228
+ done(null, undefined);
347
229
  return;
348
230
  }
349
-
350
- if (reply.sent) {
351
- /**
352
- * At this point throwing an exception will not do anything with the response. So just log it.
353
- */
354
- console.log(JSON.stringify({
355
- message: `Output was already sent. Please check custom plugins of type "HandlerOnRequestPlugin".`,
356
- explanation: "This error can happen if the user plugin ended the reply, but did not return false as response."
357
- }));
358
- return;
359
- }
360
-
361
- reply.headers((0, _objectSpread2.default)((0, _objectSpread2.default)({}, defaultHeaders), OPTIONS_HEADERS)).code(204).send("").hijack();
362
- });
363
- app.addHook("preParsing", async (request, reply) => {
364
- app.webiny.request = request;
365
- app.webiny.reply = reply;
366
- const plugins = app.webiny.plugins.byType(_api.ContextPlugin.type);
367
- let name;
368
-
369
231
  try {
370
- for (const plugin of plugins) {
371
- name = plugin.name;
372
- await plugin.apply(app.webiny);
373
- }
374
- } catch (ex) {
375
- console.log(`Error while running the "ContextPlugin" ${name ? `(${name})` : ""} plugin in the preParsing hook.`);
376
- console.log(stringifyError(ex));
377
- throw ex;
232
+ const json = typeof body === "string" ? body : body.toString("utf8");
233
+ done(null, JSON.parse(json));
234
+ } catch (err) {
235
+ done(err);
378
236
  }
379
237
  });
238
+
380
239
  /**
240
+ * With this we ensure that an undefined request body is not parsed on OPTIONS requests,
241
+ * in case there's a `content-type` header set for whatever reason.
381
242
  *
243
+ * @see https://fastify.dev/docs/latest/Reference/ContentTypeParser/#content-type-parser
382
244
  */
383
-
384
- app.addHook("preHandler", async () => {
385
- const plugins = app.webiny.plugins.byType(_BeforeHandlerPlugin.BeforeHandlerPlugin.type);
386
- let name;
387
-
388
- try {
389
- for (const plugin of plugins) {
390
- name = plugin.name;
391
- await plugin.apply(app.webiny);
392
- }
393
- } catch (ex) {
394
- console.log(`Error while running the "BeforeHandlerPlugin" ${name ? `(${name})` : ""} plugin in the preHandler hook.`);
395
- console.log(stringifyError(ex));
396
- throw ex;
245
+ app.addHook("onRequest", async request => {
246
+ if (request.method === "OPTIONS" && request.body === undefined) {
247
+ request.headers["content-type"] = undefined;
397
248
  }
398
249
  });
250
+
399
251
  /**
400
- *
252
+ * At this point, request body is properly parsed, and we can execute Webiny business logic.
253
+ * - set default headers
254
+ * - process `HandlerOnRequestPlugin`
255
+ * - if OPTIONS request, exit early
256
+ * - process `ContextPlugin`
257
+ * - process `BeforeHandlerPlugin`
401
258
  */
259
+ app.addHook("preHandler", async (request, reply) => {
260
+ app.webiny.request = request;
261
+ app.webiny.reply = reply;
402
262
 
403
- const preSerialization = async (_, __, payload) => {
404
- const plugins = app.webiny.plugins.byType(_HandlerResultPlugin.HandlerResultPlugin.type);
263
+ // Bind request and reply to DI container for runtime access
264
+ if (app.webiny.container) {
265
+ app.webiny.container.registerInstance(Request, request);
266
+ app.webiny.container.registerInstance(Reply, reply);
267
+ }
268
+ /**
269
+ * Default code to 200 - so we do not need to set it again.
270
+ * Usually we set errors manually when we use reply.send.
271
+ */
272
+ reply.code(200);
273
+ const handlerOnRequestPlugins = app.webiny.plugins.byType(HandlerOnRequestPlugin.type);
274
+ const contextPlugins = app.webiny.plugins.byType(ContextPlugin.type);
275
+ const beforeHandlerPlugins = app.webiny.plugins.byType(BeforeHandlerPlugin.type);
276
+ const modifyHeadersPlugins = app.webiny.plugins.byType(ModifyResponseHeadersPlugin.type);
277
+ const preHandler = new PreHandler([new SetDefaultHeaders(definedRoutes), new ProcessHandlerOnRequestPlugins(handlerOnRequestPlugins), new IfNotOptionsRequest([new ProcessContextPlugins(app.webiny, contextPlugins), new ProcessBeforeHandlerPlugins(app.webiny, beforeHandlerPlugins)]), new IfOptionsRequest([new SendEarlyOptionsResponse(modifyHeadersPlugins)])]);
278
+ await preHandler.execute(request, reply, app.webiny);
279
+ });
280
+ app.addHook("preSerialization", async (_, __, payload) => {
281
+ const plugins = app.webiny.plugins.byType(HandlerResultPlugin.type);
405
282
  let name;
406
-
407
283
  try {
408
284
  for (const plugin of plugins) {
409
285
  name = plugin.name;
410
286
  await plugin.handle(app.webiny, payload);
411
287
  }
412
288
  } catch (ex) {
413
- console.log(`Error while running the "HandlerResultPlugin" ${name ? `(${name})` : ""} plugin in the preSerialization hook.`);
414
- console.log(stringifyError(ex));
289
+ console.error(`Error while running the "HandlerResultPlugin" ${name ? `(${name})` : ""} plugin in the preSerialization hook.`);
290
+ console.error(stringifyError(ex));
415
291
  throw ex;
416
292
  }
417
-
418
293
  return payload;
419
- };
420
-
421
- app.addHook("preSerialization", preSerialization);
422
- app.setErrorHandler(async (error, request, reply) => {
294
+ });
295
+ app.setErrorHandler(async (error, _, reply) => {
296
+ /**
297
+ * IMPORTANT! Do not send anything if reply was already sent.
298
+ */
299
+ if (reply.sent) {
300
+ console.warn("Reply already sent, cannot send the result (handler:setErrorHandler).");
301
+ return reply;
302
+ }
303
+ if (error.code?.startsWith("Authentication/")) {
304
+ return reply.status(401).headers({
305
+ "Cache-Control": "no-store"
306
+ }).send(JSON.stringify({
307
+ message: error.message,
308
+ code: error.code
309
+ }));
310
+ }
311
+ if (error.code === "Tenancy/TenantDisabled") {
312
+ return reply.status(503).headers({
313
+ "Cache-Control": "no-store"
314
+ }).send(JSON.stringify({
315
+ message: error.message,
316
+ code: error.code
317
+ }));
318
+ }
423
319
  return reply.status(500).headers({
424
320
  "Cache-Control": "no-store"
425
321
  }).send(
@@ -433,25 +329,37 @@ const createHandler = params => {
433
329
  }));
434
330
  });
435
331
  app.addHook("onError", async (_, reply, error) => {
436
- const plugins = app.webiny.plugins.byType(_HandlerErrorPlugin.HandlerErrorPlugin.type);
332
+ const plugins = app.webiny.plugins.byType(HandlerErrorPlugin.type);
437
333
  /**
438
334
  * Log error to cloud, as these can be extremely annoying to debug!
439
335
  */
440
-
441
- console.log("@webiny/handler");
442
- console.log(stringifyError(error));
443
- reply.status(500).headers({
444
- "Cache-Control": "no-store"
445
- }).send(
336
+ console.error("Logging error in @webiny/handler");
337
+ try {
338
+ console.error(stringifyError(error));
339
+ } catch (ex) {
340
+ console.warn("Could not stringify error:");
341
+ console.log(error);
342
+ console.error("Stringify error:", ex);
343
+ }
446
344
  /**
447
- * When we are sending the error in the response, we cannot send the whole error object, as it might contain some sensitive data.
345
+ * IMPORTANT! Do not send anything if reply was already sent.
448
346
  */
449
- JSON.stringify({
450
- message: error.message,
451
- code: error.code,
452
- data: error.data
453
- }));
454
- const handler = (0, _middleware.middleware)(plugins.map(pl => {
347
+ if (!reply.sent) {
348
+ reply.status(500).headers({
349
+ "Cache-Control": "no-store"
350
+ }).send(
351
+ /**
352
+ * When we are sending the error in the response, we cannot send the whole error object, as it might contain some sensitive data.
353
+ */
354
+ JSON.stringify({
355
+ message: error.message,
356
+ code: error.code,
357
+ data: error.data
358
+ }));
359
+ } else {
360
+ console.warn("Reply already sent, cannot send the result (handler:addHook:onError).");
361
+ }
362
+ const handler = middleware(plugins.map(pl => {
455
363
  return (context, error, next) => {
456
364
  return pl.handle(context, error, next);
457
365
  };
@@ -459,25 +367,77 @@ const createHandler = params => {
459
367
  await handler(app.webiny, error);
460
368
  return reply;
461
369
  });
370
+
462
371
  /**
463
- * With these plugins we give users possibility to do anything they want on our fastify instance.
372
+ * Apply response headers modifier plugins.
464
373
  */
374
+ app.addHook("onSend", async (request, reply, input) => {
375
+ modifyResponseHeaders(app, request, reply);
376
+ const plugins = app.webiny.plugins.byType(OnRequestResponseSendPlugin.type);
377
+ let payload = input;
378
+ for (const plugin of plugins) {
379
+ payload = await plugin.exec(request, reply, payload);
380
+ }
381
+ return payload;
382
+ });
465
383
 
466
- const modifyPlugins = app.webiny.plugins.byType(_ModifyFastifyPlugin.ModifyFastifyPlugin.type);
467
- let modifyFastifyPluginName;
384
+ /**
385
+ * We need to output the benchmark results at the end of the request in both response and timeout cases
386
+ */
387
+ app.addHook("onResponse", async () => {
388
+ await context.benchmark.output();
389
+ });
390
+ app.addHook("onTimeout", async (request, reply) => {
391
+ const plugins = app.webiny.plugins.byType(OnRequestTimeoutPlugin.type);
392
+ for (const plugin of plugins) {
393
+ await plugin.exec(request, reply);
394
+ }
395
+ await context.benchmark.output();
396
+ });
468
397
 
398
+ /**
399
+ * With these plugins we give users possibility to do anything they want on our fastify instance.
400
+ */
401
+ const modifyPlugins = app.webiny.plugins.byType(ModifyFastifyPlugin.type);
402
+ let modifyFastifyPluginName;
469
403
  try {
470
404
  for (const plugin of modifyPlugins) {
471
405
  modifyFastifyPluginName = plugin.name;
472
406
  plugin.modify(app);
473
407
  }
474
408
  } catch (ex) {
475
- console.log(`Error while running the "ModifyFastifyPlugin" ${modifyFastifyPluginName ? `(${modifyFastifyPluginName})` : ""} plugin in the end of the "createHandler" callable.`);
476
- console.log(stringifyError(ex));
409
+ console.error(`Error while running the "ModifyFastifyPlugin" ${modifyFastifyPluginName ? `(${modifyFastifyPluginName})` : ""} plugin in the end of the "createHandler" callable.`);
410
+ console.error(stringifyError(ex));
477
411
  throw ex;
478
412
  }
479
413
 
414
+ /**
415
+ * We have few types of triggers:
416
+ * * Events - EventPlugin
417
+ * * Routes - RoutePlugin
418
+ *
419
+ * Routes are registered in fastify but events must be handled in package which implements cloud specific methods.
420
+ */
421
+ const routePlugins = app.webiny.plugins.byType(RoutePlugin.type);
422
+
423
+ /**
424
+ * Add routes to the system.
425
+ */
426
+ let routePluginName;
427
+ try {
428
+ for (const plugin of routePlugins) {
429
+ routePluginName = plugin.name;
430
+ plugin.cb({
431
+ ...app.webiny.routes,
432
+ context: app.webiny
433
+ });
434
+ }
435
+ } catch (ex) {
436
+ console.error(`Error while running the "RoutePlugin" ${routePluginName ? `(${routePluginName})` : ""} plugin in the beginning of the "createHandler" callable.`);
437
+ console.error(stringifyError(ex));
438
+ throw ex;
439
+ }
480
440
  return app;
481
441
  };
482
442
 
483
- exports.createHandler = createHandler;
443
+ //# sourceMappingURL=fastify.js.map