@jaypie/express 1.1.16 → 1.1.18-rc.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.
Files changed (65) hide show
  1. package/dist/cjs/__tests__/constants.spec.d.ts +1 -0
  2. package/dist/cjs/__tests__/cors.helper.spec.d.ts +1 -0
  3. package/dist/cjs/__tests__/cors.helper.supertest.spec.d.ts +1 -0
  4. package/dist/cjs/__tests__/decorateResponse.helper.spec.d.ts +1 -0
  5. package/dist/cjs/__tests__/echo.handler.spec.d.ts +1 -0
  6. package/dist/cjs/__tests__/expressHandler.spec.d.ts +1 -0
  7. package/dist/cjs/__tests__/getCurrentInvokeUuid.adapter.spec.d.ts +1 -0
  8. package/dist/cjs/__tests__/http.handler.spec.d.ts +1 -0
  9. package/dist/cjs/__tests__/index.spec.d.ts +1 -0
  10. package/dist/cjs/__tests__/routes.spec.d.ts +1 -0
  11. package/dist/cjs/__tests__/summarizeRequest.helper.spec.d.ts +1 -0
  12. package/dist/cjs/__tests__/summarizeResponse.helper.spec.d.ts +1 -0
  13. package/dist/cjs/__tests__/supertest.spec.d.ts +1 -0
  14. package/dist/cjs/constants.d.ts +8 -0
  15. package/dist/cjs/cors.helper.d.ts +9 -0
  16. package/dist/cjs/decorateResponse.helper.d.ts +7 -0
  17. package/dist/cjs/echo.handler.d.ts +8 -0
  18. package/dist/cjs/expressHandler.d.ts +14 -0
  19. package/dist/cjs/getCurrentInvokeUuid.adapter.d.ts +2 -0
  20. package/dist/cjs/http.handler.d.ts +4 -0
  21. package/dist/cjs/index.cjs +632 -0
  22. package/dist/cjs/index.cjs.map +1 -0
  23. package/{src/index.js → dist/cjs/index.d.ts} +2 -0
  24. package/dist/cjs/routes.d.ts +8 -0
  25. package/dist/cjs/summarizeRequest.helper.d.ts +11 -0
  26. package/dist/cjs/summarizeResponse.helper.d.ts +9 -0
  27. package/dist/esm/__tests__/constants.spec.d.ts +1 -0
  28. package/dist/esm/__tests__/cors.helper.spec.d.ts +1 -0
  29. package/dist/esm/__tests__/cors.helper.supertest.spec.d.ts +1 -0
  30. package/dist/esm/__tests__/decorateResponse.helper.spec.d.ts +1 -0
  31. package/dist/esm/__tests__/echo.handler.spec.d.ts +1 -0
  32. package/dist/esm/__tests__/expressHandler.spec.d.ts +1 -0
  33. package/dist/esm/__tests__/getCurrentInvokeUuid.adapter.spec.d.ts +1 -0
  34. package/dist/esm/__tests__/http.handler.spec.d.ts +1 -0
  35. package/dist/esm/__tests__/index.spec.d.ts +1 -0
  36. package/dist/esm/__tests__/routes.spec.d.ts +1 -0
  37. package/dist/esm/__tests__/summarizeRequest.helper.spec.d.ts +1 -0
  38. package/dist/esm/__tests__/summarizeResponse.helper.spec.d.ts +1 -0
  39. package/dist/esm/__tests__/supertest.spec.d.ts +1 -0
  40. package/dist/esm/constants.d.ts +8 -0
  41. package/dist/esm/cors.helper.d.ts +9 -0
  42. package/dist/esm/decorateResponse.helper.d.ts +7 -0
  43. package/dist/esm/echo.handler.d.ts +8 -0
  44. package/dist/esm/expressHandler.d.ts +14 -0
  45. package/dist/esm/getCurrentInvokeUuid.adapter.d.ts +2 -0
  46. package/dist/esm/http.handler.d.ts +4 -0
  47. package/dist/esm/index.d.ts +7 -0
  48. package/dist/esm/index.js +619 -0
  49. package/dist/esm/index.js.map +1 -0
  50. package/dist/esm/routes.d.ts +8 -0
  51. package/dist/esm/summarizeRequest.helper.d.ts +11 -0
  52. package/dist/esm/summarizeResponse.helper.d.ts +9 -0
  53. package/package.json +35 -25
  54. package/index.d.ts +0 -68
  55. package/rollup.config.mjs +0 -22
  56. package/src/constants.js +0 -12
  57. package/src/cors.helper.js +0 -110
  58. package/src/decorateResponse.helper.js +0 -90
  59. package/src/echo.handler.js +0 -31
  60. package/src/expressHandler.js +0 -346
  61. package/src/getCurrentInvokeUuid.adapter.js +0 -33
  62. package/src/http.handler.js +0 -73
  63. package/src/routes.js +0 -43
  64. package/src/summarizeRequest.helper.js +0 -28
  65. package/src/summarizeResponse.helper.js +0 -25
@@ -0,0 +1,619 @@
1
+ import { CorsError } from '@jaypie/errors';
2
+ import { force, envBoolean, log, JAYPIE, HTTP, validate, getHeaderFrom, jaypieHandler, UnhandledError, GatewayTimeoutError, UnavailableError, BadGatewayError, InternalError, TeapotError, GoneError, MethodNotAllowedError, NotFoundError, ForbiddenError, UnauthorizedError, BadRequestError, NotImplementedError } from '@jaypie/core';
3
+ import expressCors from 'cors';
4
+ import { hasDatadogEnv, submitMetric, DATADOG } from '@jaypie/datadog';
5
+ import { getCurrentInvoke } from '@codegenie/serverless-express';
6
+
7
+ //
8
+ //
9
+ // Constants
10
+ //
11
+ const EXPRESS = {
12
+ PATH: {
13
+ ANY: "*",
14
+ ID: "/:id",
15
+ ROOT: /^\/?$/,
16
+ },
17
+ };
18
+
19
+ //
20
+ //
21
+ // Constants
22
+ //
23
+ const HTTP_PROTOCOL = "http://";
24
+ const HTTPS_PROTOCOL = "https://";
25
+ const SANDBOX_ENV = "sandbox";
26
+ //
27
+ //
28
+ // Helper Functions
29
+ //
30
+ const ensureProtocol = (url) => {
31
+ if (!url)
32
+ return url;
33
+ if (url.startsWith(HTTP_PROTOCOL) || url.startsWith(HTTPS_PROTOCOL))
34
+ return url;
35
+ return HTTPS_PROTOCOL + url;
36
+ };
37
+ const dynamicOriginCallbackHandler = (origin) => {
38
+ return (requestOrigin, callback) => {
39
+ // Handle wildcard origin
40
+ if (origin === "*") {
41
+ callback(null, true);
42
+ return;
43
+ }
44
+ // Allow requests with no origin (like mobile apps, curl, etc)
45
+ if (!requestOrigin) {
46
+ callback(null, true);
47
+ return;
48
+ }
49
+ const allowedOrigins = [];
50
+ if (process.env.BASE_URL) {
51
+ allowedOrigins.push(ensureProtocol(process.env.BASE_URL));
52
+ }
53
+ if (process.env.PROJECT_BASE_URL) {
54
+ allowedOrigins.push(ensureProtocol(process.env.PROJECT_BASE_URL));
55
+ }
56
+ if (origin) {
57
+ const additionalOrigins = force.array(origin);
58
+ allowedOrigins.push(...additionalOrigins);
59
+ }
60
+ // Add localhost origins in sandbox
61
+ if (process.env.PROJECT_ENV === SANDBOX_ENV ||
62
+ envBoolean("PROJECT_SANDBOX_MODE")) {
63
+ allowedOrigins.push("http://localhost");
64
+ allowedOrigins.push(/^http:\/\/localhost:\d+$/);
65
+ }
66
+ const isAllowed = allowedOrigins.some((allowed) => {
67
+ if (allowed instanceof RegExp) {
68
+ return allowed.test(requestOrigin);
69
+ }
70
+ return requestOrigin.includes(allowed);
71
+ });
72
+ if (isAllowed) {
73
+ callback(null, true);
74
+ }
75
+ else {
76
+ callback(new CorsError());
77
+ }
78
+ };
79
+ };
80
+ //
81
+ //
82
+ // Main
83
+ //
84
+ const corsHelper = (config = {}) => {
85
+ const { origin, overrides = {} } = config;
86
+ const options = {
87
+ origin: dynamicOriginCallbackHandler(origin),
88
+ // * The default behavior is to allow any headers and methods so they are not included here
89
+ ...overrides,
90
+ };
91
+ return expressCors(options);
92
+ };
93
+ var cors_helper = (config) => {
94
+ const cors = corsHelper(config);
95
+ return (req, res, next) => {
96
+ cors(req, res, (error) => {
97
+ if (error) {
98
+ const corsError = error;
99
+ res.status(corsError.status);
100
+ res.setHeader("Content-Type", "application/json");
101
+ return res.json(corsError.body());
102
+ }
103
+ next();
104
+ });
105
+ };
106
+ };
107
+
108
+ //
109
+ //
110
+ // Helper Functions
111
+ //
112
+ // Adapter for the "@codegenie/serverless-express" uuid
113
+ function getServerlessExpressUuid() {
114
+ const currentInvoke = getCurrentInvoke();
115
+ if (currentInvoke &&
116
+ currentInvoke.context &&
117
+ currentInvoke.context.awsRequestId) {
118
+ return currentInvoke.context.awsRequestId;
119
+ }
120
+ return undefined;
121
+ }
122
+ //
123
+ //
124
+ // Main
125
+ //
126
+ const getCurrentInvokeUuid = () => getServerlessExpressUuid();
127
+
128
+ //
129
+ //
130
+ // Main
131
+ //
132
+ const decorateResponse = (res, { handler = "", version = process.env.PROJECT_VERSION, } = {}) => {
133
+ const log$1 = log.lib({
134
+ lib: JAYPIE.LIB.EXPRESS,
135
+ });
136
+ //
137
+ //
138
+ // Validate
139
+ //
140
+ if (typeof res !== "object" || res === null) {
141
+ log$1.warn("decorateResponse called but response is not an object");
142
+ return;
143
+ }
144
+ try {
145
+ //
146
+ //
147
+ // Decorate Headers
148
+ //
149
+ // X-Powered-By, override "Express" but nothing else
150
+ if (!res.get(HTTP.HEADER.POWERED_BY) ||
151
+ res.get(HTTP.HEADER.POWERED_BY) === "Express") {
152
+ res.set(HTTP.HEADER.POWERED_BY, JAYPIE.LIB.EXPRESS);
153
+ }
154
+ // X-Project-Environment
155
+ if (process.env.PROJECT_ENV) {
156
+ res.set(HTTP.HEADER.PROJECT.ENVIRONMENT, process.env.PROJECT_ENV);
157
+ }
158
+ // X-Project-Handler
159
+ if (handler) {
160
+ res.set(HTTP.HEADER.PROJECT.HANDLER, handler);
161
+ }
162
+ // X-Project-Invocation
163
+ const currentInvoke = getCurrentInvokeUuid();
164
+ if (currentInvoke) {
165
+ res.set(HTTP.HEADER.PROJECT.INVOCATION, currentInvoke);
166
+ }
167
+ // X-Project-Key
168
+ if (process.env.PROJECT_KEY) {
169
+ res.set(HTTP.HEADER.PROJECT.KEY, process.env.PROJECT_KEY);
170
+ }
171
+ // X-Project-Version
172
+ if (version) {
173
+ res.set(HTTP.HEADER.PROJECT.VERSION, version);
174
+ }
175
+ //
176
+ //
177
+ // Error Handling
178
+ //
179
+ }
180
+ catch (error) {
181
+ log$1.warn("decorateResponse caught an internal error");
182
+ log$1.var({ error });
183
+ }
184
+ };
185
+ //
186
+ //
187
+ // Footnotes
188
+ //
189
+ // This is a "utility" function but it needs a lot of "context"
190
+ // about the environment's secret parameters, the special adapter,
191
+ // HTTP, etc. There must be a better way to organize this
192
+
193
+ //
194
+ //
195
+ // Function Definition
196
+ //
197
+ function summarizeRequest(req) {
198
+ // If body is a buffer, convert it to a string
199
+ let { body } = req;
200
+ if (Buffer.isBuffer(body)) {
201
+ body = body.toString();
202
+ }
203
+ return {
204
+ baseUrl: req.baseUrl,
205
+ body,
206
+ headers: req.headers,
207
+ method: req.method,
208
+ query: req.query,
209
+ url: req.url,
210
+ };
211
+ }
212
+
213
+ //
214
+ //
215
+ // Function Definition
216
+ //
217
+ function summarizeResponse(res, extras) {
218
+ const response = {
219
+ statusCode: res.statusCode,
220
+ statusMessage: res.statusMessage,
221
+ };
222
+ if (typeof res.getHeaders === "function") {
223
+ response.headers = res.getHeaders();
224
+ }
225
+ if (typeof extras === "object" && extras !== null) {
226
+ Object.assign(response, extras);
227
+ }
228
+ return response;
229
+ }
230
+
231
+ // Cast logger to extended interface for runtime features not in type definitions
232
+ const logger = log;
233
+ function expressHandler(handlerOrOptions, optionsOrHandler) {
234
+ /* eslint-enable no-redeclare */
235
+ let handler;
236
+ let options;
237
+ // If handler is an object and options is a function, swap them
238
+ if (typeof handlerOrOptions === "object" &&
239
+ typeof optionsOrHandler === "function") {
240
+ handler = optionsOrHandler;
241
+ options = handlerOrOptions;
242
+ }
243
+ else {
244
+ handler = handlerOrOptions;
245
+ options = (optionsOrHandler || {});
246
+ }
247
+ //
248
+ //
249
+ // Validate
250
+ //
251
+ let { chaos, locals, name, setup = [], teardown = [], unavailable, validate: validate$1, } = options;
252
+ validate.function(handler);
253
+ validate.optional.object(locals);
254
+ setup = force.array(setup); // allows a single item
255
+ teardown = force.array(teardown); // allows a single item
256
+ //
257
+ //
258
+ // Setup
259
+ //
260
+ let jaypieFunction;
261
+ return async (req, res, ...params) => {
262
+ // * This is the first line of code that runs when a request is received
263
+ const extReq = req;
264
+ const extRes = res;
265
+ // Set default chaos value
266
+ if (chaos === undefined) {
267
+ chaos =
268
+ process.env.PROJECT_CHAOS ||
269
+ getHeaderFrom("X-Project-Chaos", req);
270
+ }
271
+ // Re-init the logger
272
+ logger.init();
273
+ // Very low-level, internal sub-trace details
274
+ const libLogger = logger.lib({
275
+ lib: JAYPIE.LIB.EXPRESS,
276
+ });
277
+ // Top-level, important details that run at the same level as the main logger
278
+ const log = logger.lib({
279
+ level: logger.level,
280
+ lib: JAYPIE.LIB.EXPRESS,
281
+ });
282
+ // Update the public logger with the request ID
283
+ const invokeUuid = getCurrentInvokeUuid();
284
+ if (invokeUuid) {
285
+ logger.tag({ invoke: invokeUuid });
286
+ logger.tag({ shortInvoke: invokeUuid.slice(0, 8) });
287
+ // TODO: in theory this is redundant
288
+ libLogger.tag({ invoke: invokeUuid });
289
+ libLogger.tag({ shortInvoke: invokeUuid.slice(0, 8) });
290
+ log.tag({ invoke: invokeUuid });
291
+ log.tag({ shortInvoke: invokeUuid.slice(0, 8) });
292
+ }
293
+ if (!name) {
294
+ // If handler has a name, use it
295
+ if (handler.name) {
296
+ name = handler.name;
297
+ }
298
+ else {
299
+ name = JAYPIE.UNKNOWN;
300
+ }
301
+ }
302
+ logger.tag({ handler: name });
303
+ // TODO: in theory this is redundant
304
+ libLogger.tag({ handler: name });
305
+ log.tag({ handler: name });
306
+ libLogger.trace("[jaypie] Express init");
307
+ // Set req.locals if it doesn't exist
308
+ if (!extReq.locals)
309
+ extReq.locals = {};
310
+ if (!extReq.locals._jaypie)
311
+ extReq.locals._jaypie = {};
312
+ // Set res.locals if it doesn't exist
313
+ if (!extRes.locals)
314
+ extRes.locals = {};
315
+ if (!extRes.locals._jaypie)
316
+ extRes.locals._jaypie = {};
317
+ const originalRes = {
318
+ attemptedCall: undefined,
319
+ attemptedParams: undefined,
320
+ end: res.end.bind(res),
321
+ json: res.json.bind(res),
322
+ send: res.send.bind(res),
323
+ status: res.status.bind(res),
324
+ statusSent: false,
325
+ };
326
+ res.end = ((...endParams) => {
327
+ originalRes.attemptedCall = originalRes.end;
328
+ originalRes.attemptedParams = endParams;
329
+ log.warn("[jaypie] Illegal call to res.end(); prefer Jaypie response conventions");
330
+ return res;
331
+ });
332
+ res.json = ((...jsonParams) => {
333
+ originalRes.attemptedCall = originalRes.json;
334
+ originalRes.attemptedParams = jsonParams;
335
+ log.warn("[jaypie] Illegal call to res.json(); prefer Jaypie response conventions");
336
+ return res;
337
+ });
338
+ res.send = ((...sendParams) => {
339
+ originalRes.attemptedCall = originalRes.send;
340
+ originalRes.attemptedParams = sendParams;
341
+ log.warn("[jaypie] Illegal call to res.send(); prefer Jaypie response conventions");
342
+ return res;
343
+ });
344
+ res.status = ((...statusParams) => {
345
+ originalRes.statusSent = statusParams[0];
346
+ return originalRes.status(...statusParams);
347
+ });
348
+ //
349
+ //
350
+ // Preprocess
351
+ //
352
+ if (locals) {
353
+ // Locals
354
+ const keys = Object.keys(locals);
355
+ if (keys.length > 0) {
356
+ const localsSetup = async (localsReq, localsRes) => {
357
+ const extLocalsReq = localsReq;
358
+ for (let i = 0; i < keys.length; i += 1) {
359
+ const key = keys[i];
360
+ libLogger.trace(`[jaypie] Locals: ${key}`);
361
+ const localValue = locals[key];
362
+ if (typeof localValue === "function") {
363
+ extLocalsReq.locals[key] = await localValue(localsReq, localsRes);
364
+ }
365
+ else {
366
+ extLocalsReq.locals[key] = localValue;
367
+ }
368
+ }
369
+ };
370
+ setup.push(localsSetup);
371
+ }
372
+ }
373
+ let response;
374
+ let status = HTTP.CODE.OK;
375
+ try {
376
+ log.info.var({ req: summarizeRequest(req) });
377
+ // Initialize after logging is set up
378
+ jaypieFunction = jaypieHandler(handler, {
379
+ chaos,
380
+ name,
381
+ setup,
382
+ teardown,
383
+ unavailable,
384
+ validate: validate$1,
385
+ });
386
+ libLogger.trace("[jaypie] Express execution");
387
+ //
388
+ //
389
+ // Process
390
+ //
391
+ response = (await jaypieFunction(req, res, ...params));
392
+ //
393
+ //
394
+ // Error Handling
395
+ //
396
+ }
397
+ catch (error) {
398
+ // In theory jaypieFunction has handled all errors
399
+ const jaypieError = error;
400
+ if (jaypieError.status) {
401
+ status = jaypieError.status;
402
+ }
403
+ if (typeof jaypieError.json === "function") {
404
+ response = jaypieError.json();
405
+ }
406
+ else {
407
+ // This should never happen
408
+ const unhandledError = new UnhandledError();
409
+ response = unhandledError.json();
410
+ status = unhandledError.status;
411
+ }
412
+ }
413
+ //
414
+ //
415
+ // Postprocess
416
+ //
417
+ // Restore original res functions
418
+ res.end = originalRes.end;
419
+ res.json = originalRes.json;
420
+ res.send = originalRes.send;
421
+ res.status = originalRes.status;
422
+ // Decorate response
423
+ decorateResponse(res, { handler: name });
424
+ // Allow the sent status to override the status in the response
425
+ if (originalRes.statusSent) {
426
+ status = originalRes.statusSent;
427
+ }
428
+ // Send response
429
+ try {
430
+ if (!originalRes.attemptedCall) {
431
+ // Body
432
+ if (response) {
433
+ if (typeof response === "object") {
434
+ if (typeof response.json ===
435
+ "function") {
436
+ res.json(response.json());
437
+ }
438
+ else {
439
+ res.status(status).json(response);
440
+ }
441
+ }
442
+ else if (typeof response === "string") {
443
+ try {
444
+ res.status(status).json(JSON.parse(response));
445
+ }
446
+ catch {
447
+ res.status(status).send(response);
448
+ }
449
+ }
450
+ else if (response === true) {
451
+ res.status(HTTP.CODE.CREATED).send();
452
+ }
453
+ else {
454
+ res.status(status).send(response);
455
+ }
456
+ }
457
+ else {
458
+ // No response
459
+ res.status(HTTP.CODE.NO_CONTENT).send();
460
+ }
461
+ }
462
+ else {
463
+ // Resolve illegal call to res.end(), res.json(), or res.send()
464
+ log.debug("[jaypie] Resolving illegal call to res");
465
+ log.var({
466
+ attemptedCall: {
467
+ name: originalRes.attemptedCall.name,
468
+ params: originalRes.attemptedParams,
469
+ },
470
+ });
471
+ // Call the original function with the original parameters and the original `this` (res)
472
+ originalRes.attemptedCall.call(res, ...(originalRes.attemptedParams || []));
473
+ }
474
+ }
475
+ catch (error) {
476
+ log.fatal("Express encountered an error while sending the response");
477
+ log.var({ responseError: error });
478
+ }
479
+ // Log response
480
+ const extras = {};
481
+ if (response)
482
+ extras.body = response;
483
+ log.info.var({
484
+ res: summarizeResponse(res, extras),
485
+ });
486
+ // Submit metric if Datadog is configured
487
+ if (hasDatadogEnv()) {
488
+ // Construct path from baseUrl and url
489
+ let path = (req.baseUrl || "") + (req.url || "");
490
+ // Ensure path starts with /
491
+ if (!path.startsWith("/")) {
492
+ path = "/" + path;
493
+ }
494
+ // Remove trailing slash unless it's the root path
495
+ if (path.length > 1 && path.endsWith("/")) {
496
+ path = path.slice(0, -1);
497
+ }
498
+ // Replace UUIDs with :id for better aggregation
499
+ // Matches standard UUID v4 format (8-4-4-4-12 hex characters)
500
+ path = path.replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, ":id");
501
+ // Determine metric name based on environment variables
502
+ let metricPrefix = "project";
503
+ if (process.env.PROJECT_SPONSOR) {
504
+ metricPrefix = process.env.PROJECT_SPONSOR;
505
+ }
506
+ else if (process.env.PROJECT_KEY) {
507
+ metricPrefix = `project.${process.env.PROJECT_KEY}`;
508
+ }
509
+ await submitMetric({
510
+ name: `${metricPrefix}.api.response`,
511
+ type: DATADOG.METRIC.TYPE.COUNT,
512
+ value: 1,
513
+ tags: {
514
+ status: String(res.statusCode),
515
+ path,
516
+ },
517
+ });
518
+ }
519
+ // Clean up the public logger
520
+ logger.untag("handler");
521
+ //
522
+ //
523
+ // Return
524
+ //
525
+ return response;
526
+ };
527
+ }
528
+
529
+ //
530
+ //
531
+ // Main
532
+ //
533
+ const httpHandler = (statusCode = HTTP.CODE.OK, context = {}) => {
534
+ // Give a default name if there isn't one
535
+ if (!context.name) {
536
+ context.name = "_http";
537
+ }
538
+ // Return a function that will be used as an express route
539
+ return expressHandler(async (req, res) => {
540
+ // Map the most throwable status codes to errors and throw them!
541
+ const error = {
542
+ [HTTP.CODE.BAD_REQUEST]: BadRequestError,
543
+ [HTTP.CODE.UNAUTHORIZED]: UnauthorizedError,
544
+ [HTTP.CODE.FORBIDDEN]: ForbiddenError,
545
+ [HTTP.CODE.NOT_FOUND]: NotFoundError,
546
+ [HTTP.CODE.METHOD_NOT_ALLOWED]: MethodNotAllowedError,
547
+ [HTTP.CODE.GONE]: GoneError,
548
+ [HTTP.CODE.TEAPOT]: TeapotError,
549
+ [HTTP.CODE.INTERNAL_ERROR]: InternalError,
550
+ [HTTP.CODE.BAD_GATEWAY]: BadGatewayError,
551
+ [HTTP.CODE.UNAVAILABLE]: UnavailableError,
552
+ [HTTP.CODE.GATEWAY_TIMEOUT]: GatewayTimeoutError,
553
+ };
554
+ // If this maps to an error, throw it
555
+ if (error[statusCode]) {
556
+ log.trace(`@knowdev/express: gracefully throwing ${statusCode} up to projectHandler`);
557
+ throw new error[statusCode]();
558
+ }
559
+ // If this is an error and we didn't get thrown, log a warning
560
+ if (statusCode >= 400) {
561
+ log.warn(`@knowdev/express: status code ${statusCode} not mapped as throwable`);
562
+ }
563
+ // Send the response
564
+ res.status(statusCode);
565
+ return statusCode === HTTP.CODE.NO_CONTENT ? null : {};
566
+ }, context);
567
+ };
568
+
569
+ //
570
+ //
571
+ // Main
572
+ //
573
+ const echoHandler = (context = {}) => {
574
+ validate.object(context);
575
+ // Give a default name if there isn't one
576
+ if (!context.name) {
577
+ context.name = "_echo";
578
+ }
579
+ // Return a function that will be used as an express route
580
+ return expressHandler(async (req) => {
581
+ return {
582
+ req: summarizeRequest(req),
583
+ };
584
+ }, context);
585
+ };
586
+
587
+ //
588
+ //
589
+ // Functions
590
+ //
591
+ const routes = {
592
+ badRequestRoute: httpHandler(HTTP.CODE.BAD_REQUEST, { name: "_badRequest" }),
593
+ echoRoute: echoHandler(),
594
+ forbiddenRoute: httpHandler(HTTP.CODE.FORBIDDEN, { name: "_forbidden" }),
595
+ goneRoute: httpHandler(HTTP.CODE.GONE, { name: "_gone" }),
596
+ methodNotAllowedRoute: httpHandler(HTTP.CODE.METHOD_NOT_ALLOWED, {
597
+ name: "_methodNotAllowed",
598
+ }),
599
+ noContentRoute: httpHandler(HTTP.CODE.NO_CONTENT, { name: "_noContent" }),
600
+ notFoundRoute: httpHandler(HTTP.CODE.NOT_FOUND, { name: "_notFound" }),
601
+ notImplementedRoute: expressHandler(() => {
602
+ throw new NotImplementedError();
603
+ }, { name: "_notImplemented" }),
604
+ };
605
+ //
606
+ //
607
+ // Export
608
+ //
609
+ const badRequestRoute = routes.badRequestRoute;
610
+ const echoRoute = routes.echoRoute;
611
+ const forbiddenRoute = routes.forbiddenRoute;
612
+ const goneRoute = routes.goneRoute;
613
+ const methodNotAllowedRoute = routes.methodNotAllowedRoute;
614
+ const noContentRoute = routes.noContentRoute;
615
+ const notFoundRoute = routes.notFoundRoute;
616
+ const notImplementedRoute = routes.notImplementedRoute;
617
+
618
+ export { EXPRESS, badRequestRoute, cors_helper as cors, echoRoute, expressHandler, httpHandler as expressHttpCodeHandler, forbiddenRoute, goneRoute, methodNotAllowedRoute, noContentRoute, notFoundRoute, notImplementedRoute };
619
+ //# sourceMappingURL=index.js.map