@jaypie/express 1.2.3 → 1.2.4-rc0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/esm/index.js CHANGED
@@ -1,10 +1,584 @@
1
+ import { Readable, Writable } from 'node:stream';
1
2
  import { CorsError, BadRequestError, UnhandledError, GatewayTimeoutError, UnavailableError, BadGatewayError, InternalError, TeapotError, GoneError, MethodNotAllowedError, NotFoundError, ForbiddenError, UnauthorizedError, NotImplementedError } from '@jaypie/errors';
2
3
  import { force, envBoolean, JAYPIE, HTTP, getHeaderFrom, jaypieHandler } from '@jaypie/kit';
3
4
  import expressCors from 'cors';
4
5
  import { log } from '@jaypie/logger';
5
6
  import { loadEnvSecrets } from '@jaypie/aws';
6
7
  import { hasDatadogEnv, submitMetric, DATADOG } from '@jaypie/datadog';
7
- import { getCurrentInvoke } from '@codegenie/serverless-express';
8
+
9
+ //
10
+ //
11
+ // LambdaRequest Class
12
+ //
13
+ /**
14
+ * Mock IncomingMessage that extends Readable stream.
15
+ * Provides Express-compatible request interface from Lambda Function URL events.
16
+ */
17
+ class LambdaRequest extends Readable {
18
+ constructor(options) {
19
+ super();
20
+ this.httpVersion = "1.1";
21
+ this.httpVersionMajor = 1;
22
+ this.httpVersionMinor = 1;
23
+ this.complete = false;
24
+ this.baseUrl = "";
25
+ this.params = {};
26
+ this.query = {};
27
+ this.bodyPushed = false;
28
+ this.method = options.method;
29
+ this.url = options.url;
30
+ this.originalUrl = options.url;
31
+ this.path = options.url.split("?")[0];
32
+ this.headers = this.normalizeHeaders(options.headers);
33
+ this.bodyBuffer = options.body ?? null;
34
+ // Store Lambda context
35
+ this._lambdaContext = options.lambdaContext;
36
+ this._lambdaEvent = options.lambdaEvent;
37
+ // Create mock socket
38
+ this.socket = {
39
+ destroy: () => { },
40
+ encrypted: options.protocol === "https",
41
+ remoteAddress: options.remoteAddress,
42
+ };
43
+ this.connection = this.socket;
44
+ }
45
+ //
46
+ // Readable stream implementation
47
+ //
48
+ _read() {
49
+ if (!this.bodyPushed) {
50
+ if (this.bodyBuffer && this.bodyBuffer.length > 0) {
51
+ this.push(this.bodyBuffer);
52
+ }
53
+ this.push(null); // Signal end of stream
54
+ this.bodyPushed = true;
55
+ this.complete = true;
56
+ }
57
+ }
58
+ //
59
+ // Express helper methods
60
+ //
61
+ get(headerName) {
62
+ const key = headerName.toLowerCase();
63
+ const value = this.headers[key];
64
+ return Array.isArray(value) ? value[0] : value;
65
+ }
66
+ header(headerName) {
67
+ return this.get(headerName);
68
+ }
69
+ //
70
+ // Private helpers
71
+ //
72
+ normalizeHeaders(headers) {
73
+ const normalized = {};
74
+ for (const [key, value] of Object.entries(headers)) {
75
+ normalized[key.toLowerCase()] = value;
76
+ }
77
+ return normalized;
78
+ }
79
+ }
80
+ //
81
+ //
82
+ // Factory Function
83
+ //
84
+ /**
85
+ * Create a LambdaRequest from a Function URL event.
86
+ */
87
+ function createLambdaRequest(event, context) {
88
+ // Build URL with query string
89
+ const url = event.rawQueryString
90
+ ? `${event.rawPath}?${event.rawQueryString}`
91
+ : event.rawPath;
92
+ // Decode body if present
93
+ let body = null;
94
+ if (event.body) {
95
+ body = event.isBase64Encoded
96
+ ? Buffer.from(event.body, "base64")
97
+ : Buffer.from(event.body, "utf8");
98
+ }
99
+ // Normalize cookies into Cookie header if not already present
100
+ const headers = { ...event.headers };
101
+ if (event.cookies && event.cookies.length > 0 && !headers.cookie) {
102
+ headers.cookie = event.cookies.join("; ");
103
+ }
104
+ return new LambdaRequest({
105
+ body,
106
+ headers,
107
+ lambdaContext: context,
108
+ lambdaEvent: event,
109
+ method: event.requestContext.http.method,
110
+ protocol: event.requestContext.http.protocol.split("/")[0].toLowerCase(),
111
+ remoteAddress: event.requestContext.http.sourceIp,
112
+ url,
113
+ });
114
+ }
115
+
116
+ //
117
+ //
118
+ // Constants
119
+ //
120
+ const BINARY_CONTENT_TYPE_PATTERNS = [
121
+ /^application\/octet-stream$/,
122
+ /^application\/pdf$/,
123
+ /^application\/zip$/,
124
+ /^audio\//,
125
+ /^font\//,
126
+ /^image\//,
127
+ /^video\//,
128
+ ];
129
+ //
130
+ //
131
+ // LambdaResponseBuffered Class
132
+ //
133
+ /**
134
+ * Mock ServerResponse that buffers the response.
135
+ * Collects status, headers, and body chunks, then returns a Lambda response.
136
+ */
137
+ class LambdaResponseBuffered extends Writable {
138
+ constructor() {
139
+ super();
140
+ this.statusCode = 200;
141
+ this.statusMessage = "OK";
142
+ // Mock socket to satisfy Express/finalhandler checks
143
+ this.socket = {
144
+ cork: () => { },
145
+ destroy: () => { },
146
+ remoteAddress: "127.0.0.1",
147
+ uncork: () => { },
148
+ writable: true,
149
+ };
150
+ this._chunks = [];
151
+ this._headers = new Map();
152
+ this._headersSent = false;
153
+ this._resolve = null;
154
+ }
155
+ //
156
+ // Promise-based API for getting final result
157
+ //
158
+ getResult() {
159
+ return new Promise((resolve) => {
160
+ if (this.writableEnded) {
161
+ resolve(this.buildResult());
162
+ }
163
+ else {
164
+ this._resolve = resolve;
165
+ }
166
+ });
167
+ }
168
+ //
169
+ // Header management
170
+ //
171
+ setHeader(name, value) {
172
+ if (this._headersSent) {
173
+ // In production, log warning but don't throw to match Express behavior
174
+ return this;
175
+ }
176
+ this._headers.set(name.toLowerCase(), String(value));
177
+ return this;
178
+ }
179
+ getHeader(name) {
180
+ return this._headers.get(name.toLowerCase());
181
+ }
182
+ removeHeader(name) {
183
+ this._headers.delete(name.toLowerCase());
184
+ }
185
+ getHeaders() {
186
+ const headers = {};
187
+ for (const [key, value] of this._headers) {
188
+ headers[key] = value;
189
+ }
190
+ return headers;
191
+ }
192
+ hasHeader(name) {
193
+ return this._headers.has(name.toLowerCase());
194
+ }
195
+ getHeaderNames() {
196
+ return Array.from(this._headers.keys());
197
+ }
198
+ writeHead(statusCode, statusMessageOrHeaders, headers) {
199
+ this.statusCode = statusCode;
200
+ let headersToSet;
201
+ if (typeof statusMessageOrHeaders === "string") {
202
+ this.statusMessage = statusMessageOrHeaders;
203
+ headersToSet = headers;
204
+ }
205
+ else if (statusMessageOrHeaders &&
206
+ typeof statusMessageOrHeaders === "object") {
207
+ headersToSet = statusMessageOrHeaders;
208
+ }
209
+ if (headersToSet) {
210
+ for (const [key, value] of Object.entries(headersToSet)) {
211
+ if (value !== undefined) {
212
+ this.setHeader(key, value);
213
+ }
214
+ }
215
+ }
216
+ this._headersSent = true;
217
+ return this;
218
+ }
219
+ get headersSent() {
220
+ return this._headersSent;
221
+ }
222
+ //
223
+ // Express compatibility methods
224
+ //
225
+ status(code) {
226
+ this.statusCode = code;
227
+ return this;
228
+ }
229
+ json(data) {
230
+ this.setHeader("content-type", "application/json");
231
+ this.end(JSON.stringify(data));
232
+ return this;
233
+ }
234
+ send(body) {
235
+ if (typeof body === "object" && !Buffer.isBuffer(body)) {
236
+ return this.json(body);
237
+ }
238
+ this.end(body);
239
+ return this;
240
+ }
241
+ //
242
+ // Writable stream implementation
243
+ //
244
+ _write(chunk, encoding, // eslint-disable-line no-undef
245
+ callback) {
246
+ const buffer = Buffer.isBuffer(chunk)
247
+ ? chunk
248
+ : Buffer.from(chunk, encoding);
249
+ this._chunks.push(buffer);
250
+ this._headersSent = true;
251
+ callback();
252
+ }
253
+ _final(callback) {
254
+ if (this._resolve) {
255
+ this._resolve(this.buildResult());
256
+ }
257
+ callback();
258
+ }
259
+ //
260
+ // Private helpers
261
+ //
262
+ buildResult() {
263
+ const body = Buffer.concat(this._chunks);
264
+ const contentType = this.getHeader("content-type") || "";
265
+ // Determine if response should be base64 encoded
266
+ const isBase64Encoded = this.isBinaryContentType(contentType);
267
+ // Build headers object
268
+ const headers = {};
269
+ const cookies = [];
270
+ for (const [key, value] of this._headers) {
271
+ if (key === "set-cookie") {
272
+ // Collect Set-Cookie headers for v2 response format
273
+ if (Array.isArray(value)) {
274
+ cookies.push(...value);
275
+ }
276
+ else {
277
+ cookies.push(value);
278
+ }
279
+ }
280
+ else {
281
+ headers[key] = Array.isArray(value) ? value.join(", ") : String(value);
282
+ }
283
+ }
284
+ const result = {
285
+ body: isBase64Encoded ? body.toString("base64") : body.toString("utf8"),
286
+ headers,
287
+ isBase64Encoded,
288
+ statusCode: this.statusCode,
289
+ };
290
+ // Only include cookies if present (v2 format)
291
+ if (cookies.length > 0) {
292
+ result.cookies = cookies;
293
+ }
294
+ return result;
295
+ }
296
+ isBinaryContentType(contentType) {
297
+ return BINARY_CONTENT_TYPE_PATTERNS.some((pattern) => pattern.test(contentType));
298
+ }
299
+ }
300
+
301
+ //
302
+ //
303
+ // LambdaResponseStreaming Class
304
+ //
305
+ /**
306
+ * Mock ServerResponse that streams directly to Lambda responseStream.
307
+ * Uses awslambda.HttpResponseStream.from() to set status and headers.
308
+ */
309
+ class LambdaResponseStreaming extends Writable {
310
+ constructor(responseStream) {
311
+ super();
312
+ this.statusCode = 200;
313
+ this.statusMessage = "OK";
314
+ // Mock socket to satisfy Express/finalhandler checks
315
+ this.socket = {
316
+ cork: () => { },
317
+ destroy: () => { },
318
+ remoteAddress: "127.0.0.1",
319
+ uncork: () => { },
320
+ writable: true,
321
+ };
322
+ this._headers = new Map();
323
+ this._headersSent = false;
324
+ this._pendingWrites = [];
325
+ this._wrappedStream = null;
326
+ this._responseStream = responseStream;
327
+ }
328
+ //
329
+ // Header management
330
+ //
331
+ setHeader(name, value) {
332
+ if (this._headersSent) {
333
+ // In streaming mode, log warning but don't throw
334
+ // Headers cannot be changed after body starts
335
+ return this;
336
+ }
337
+ this._headers.set(name.toLowerCase(), String(value));
338
+ return this;
339
+ }
340
+ getHeader(name) {
341
+ return this._headers.get(name.toLowerCase());
342
+ }
343
+ removeHeader(name) {
344
+ if (!this._headersSent) {
345
+ this._headers.delete(name.toLowerCase());
346
+ }
347
+ }
348
+ getHeaders() {
349
+ const headers = {};
350
+ for (const [key, value] of this._headers) {
351
+ headers[key] = value;
352
+ }
353
+ return headers;
354
+ }
355
+ hasHeader(name) {
356
+ return this._headers.has(name.toLowerCase());
357
+ }
358
+ getHeaderNames() {
359
+ return Array.from(this._headers.keys());
360
+ }
361
+ writeHead(statusCode, statusMessageOrHeaders, headers) {
362
+ if (this._headersSent) {
363
+ return this;
364
+ }
365
+ this.statusCode = statusCode;
366
+ let headersToSet;
367
+ if (typeof statusMessageOrHeaders === "string") {
368
+ this.statusMessage = statusMessageOrHeaders;
369
+ headersToSet = headers;
370
+ }
371
+ else if (statusMessageOrHeaders &&
372
+ typeof statusMessageOrHeaders === "object") {
373
+ headersToSet = statusMessageOrHeaders;
374
+ }
375
+ if (headersToSet) {
376
+ for (const [key, value] of Object.entries(headersToSet)) {
377
+ if (value !== undefined) {
378
+ this.setHeader(key, value);
379
+ }
380
+ }
381
+ }
382
+ this.flushHeaders();
383
+ return this;
384
+ }
385
+ get headersSent() {
386
+ return this._headersSent;
387
+ }
388
+ flushHeaders() {
389
+ if (this._headersSent)
390
+ return;
391
+ const headers = {};
392
+ for (const [key, value] of this._headers) {
393
+ headers[key] = Array.isArray(value) ? value.join(", ") : String(value);
394
+ }
395
+ const metadata = {
396
+ headers,
397
+ statusCode: this.statusCode,
398
+ };
399
+ // Wrap the stream with metadata using awslambda global
400
+ this._wrappedStream = awslambda.HttpResponseStream.from(this._responseStream, metadata);
401
+ this._headersSent = true;
402
+ // Flush pending writes
403
+ for (const { callback, chunk } of this._pendingWrites) {
404
+ this._wrappedStream.write(chunk);
405
+ callback();
406
+ }
407
+ this._pendingWrites = [];
408
+ }
409
+ //
410
+ // Express compatibility methods
411
+ //
412
+ status(code) {
413
+ this.statusCode = code;
414
+ return this;
415
+ }
416
+ json(data) {
417
+ this.setHeader("content-type", "application/json");
418
+ this.end(JSON.stringify(data));
419
+ return this;
420
+ }
421
+ send(body) {
422
+ if (typeof body === "object" && !Buffer.isBuffer(body)) {
423
+ return this.json(body);
424
+ }
425
+ this.end(body);
426
+ return this;
427
+ }
428
+ //
429
+ // Writable stream implementation
430
+ //
431
+ _write(chunk, encoding, // eslint-disable-line no-undef
432
+ callback) {
433
+ const buffer = Buffer.isBuffer(chunk)
434
+ ? chunk
435
+ : Buffer.from(chunk, encoding);
436
+ if (!this._headersSent) {
437
+ // Buffer writes until headers are sent
438
+ this._pendingWrites.push({ callback: () => callback(), chunk: buffer });
439
+ // Auto-flush headers on first write
440
+ this.flushHeaders();
441
+ }
442
+ else {
443
+ this._wrappedStream.write(buffer);
444
+ callback();
445
+ }
446
+ }
447
+ _final(callback) {
448
+ if (!this._headersSent) {
449
+ this.flushHeaders();
450
+ }
451
+ this._wrappedStream?.end();
452
+ callback();
453
+ }
454
+ }
455
+
456
+ //
457
+ //
458
+ // Current Invoke Context
459
+ //
460
+ let currentInvoke = null;
461
+ /**
462
+ * Get the current Lambda invoke context.
463
+ * Used by getCurrentInvokeUuid adapter to get the request ID.
464
+ */
465
+ function getCurrentInvoke() {
466
+ return currentInvoke;
467
+ }
468
+ /**
469
+ * Set the current Lambda invoke context.
470
+ * Called at the start of each Lambda invocation.
471
+ */
472
+ function setCurrentInvoke(event, context) {
473
+ currentInvoke = { context, event };
474
+ }
475
+ /**
476
+ * Clear the current Lambda invoke context.
477
+ * Called at the end of each Lambda invocation.
478
+ */
479
+ function clearCurrentInvoke() {
480
+ currentInvoke = null;
481
+ }
482
+ //
483
+ //
484
+ // Express App Runner
485
+ //
486
+ /**
487
+ * Run Express app with mock request/response.
488
+ * Returns a promise that resolves when the response is complete.
489
+ */
490
+ function runExpressApp(app, req, res) {
491
+ return new Promise((resolve, reject) => {
492
+ // Listen for response completion
493
+ res.on("finish", resolve);
494
+ res.on("error", reject);
495
+ // Run the Express app
496
+ // Cast to Express types since our mocks implement the required interface
497
+ app(req, res);
498
+ });
499
+ }
500
+ //
501
+ //
502
+ // Buffered Handler Factory
503
+ //
504
+ /**
505
+ * Create a Lambda handler that buffers the Express response.
506
+ * Returns the complete response as a Lambda response object.
507
+ *
508
+ * @example
509
+ * ```typescript
510
+ * import express from "express";
511
+ * import { createLambdaHandler } from "@jaypie/express";
512
+ *
513
+ * const app = express();
514
+ * app.get("/", (req, res) => res.json({ message: "Hello" }));
515
+ *
516
+ * export const handler = createLambdaHandler(app);
517
+ * ```
518
+ */
519
+ function createLambdaHandler(app, _options) {
520
+ return async (event, context) => {
521
+ try {
522
+ // Set current invoke for getCurrentInvokeUuid
523
+ setCurrentInvoke(event, context);
524
+ // Create mock request from Lambda event
525
+ const req = createLambdaRequest(event, context);
526
+ // Create buffered response collector
527
+ const res = new LambdaResponseBuffered();
528
+ // Run Express app
529
+ await runExpressApp(app, req, res);
530
+ // Return Lambda response
531
+ return res.getResult();
532
+ }
533
+ finally {
534
+ // Clear current invoke context
535
+ clearCurrentInvoke();
536
+ }
537
+ };
538
+ }
539
+ //
540
+ //
541
+ // Streaming Handler Factory
542
+ //
543
+ /**
544
+ * Create a Lambda handler that streams the Express response.
545
+ * Uses awslambda.streamifyResponse() for Lambda response streaming.
546
+ *
547
+ * @example
548
+ * ```typescript
549
+ * import express from "express";
550
+ * import { createLambdaStreamHandler } from "@jaypie/express";
551
+ *
552
+ * const app = express();
553
+ * app.get("/stream", (req, res) => {
554
+ * res.setHeader("Content-Type", "text/event-stream");
555
+ * res.write("data: Hello\n\n");
556
+ * res.end();
557
+ * });
558
+ *
559
+ * export const handler = createLambdaStreamHandler(app);
560
+ * ```
561
+ */
562
+ function createLambdaStreamHandler(app, _options) {
563
+ // Wrap with awslambda.streamifyResponse for Lambda streaming
564
+ // @ts-expect-error awslambda is a Lambda runtime global
565
+ return awslambda.streamifyResponse(async (event, responseStream, context) => {
566
+ try {
567
+ // Set current invoke for getCurrentInvokeUuid
568
+ setCurrentInvoke(event, context);
569
+ // Create mock request from Lambda event
570
+ const req = createLambdaRequest(event, context);
571
+ // Create streaming response that pipes to Lambda responseStream
572
+ const res = new LambdaResponseStreaming(responseStream);
573
+ // Run Express app
574
+ await runExpressApp(app, req, res);
575
+ }
576
+ finally {
577
+ // Clear current invoke context
578
+ clearCurrentInvoke();
579
+ }
580
+ });
581
+ }
8
582
 
9
583
  //
10
584
  //
@@ -256,40 +830,54 @@ function isWebAdapterMode(req) {
256
830
  return false;
257
831
  }
258
832
  /**
259
- * Adapter for the "@codegenie/serverless-express" uuid
833
+ * Get UUID from Jaypie Lambda adapter context.
834
+ * This is set by createLambdaHandler/createLambdaStreamHandler.
260
835
  */
261
- function getServerlessExpressUuid() {
836
+ function getJaypieAdapterUuid() {
262
837
  const currentInvoke = getCurrentInvoke();
263
- if (currentInvoke &&
264
- currentInvoke.context &&
265
- currentInvoke.context.awsRequestId) {
838
+ if (currentInvoke?.context?.awsRequestId) {
266
839
  return currentInvoke.context.awsRequestId;
267
840
  }
268
841
  return undefined;
269
842
  }
843
+ /**
844
+ * Get UUID from request object if it has Lambda context attached.
845
+ * The Jaypie adapter attaches _lambdaContext to the request.
846
+ */
847
+ function getRequestContextUuid(req) {
848
+ if (req && req._lambdaContext?.awsRequestId) {
849
+ return req._lambdaContext.awsRequestId;
850
+ }
851
+ return undefined;
852
+ }
270
853
  //
271
854
  //
272
855
  // Main
273
856
  //
274
857
  /**
275
858
  * Get the current invoke UUID from Lambda context.
276
- * Works in both serverless-express mode and Lambda Web Adapter mode.
859
+ * Works with Jaypie Lambda adapter and Lambda Web Adapter mode.
277
860
  *
278
- * @param req - Optional Express request object. Required for Web Adapter mode
279
- * to extract the x-amzn-request-id header.
861
+ * @param req - Optional Express request object. Used to extract context
862
+ * from Web Adapter headers or Jaypie adapter's _lambdaContext.
280
863
  * @returns The AWS request ID or undefined if not in Lambda context
281
864
  */
282
865
  function getCurrentInvokeUuid(req) {
283
- // If request is provided and has Web Adapter header, use Web Adapter mode
866
+ // Priority 1: Web Adapter mode (header-based)
284
867
  if (isWebAdapterMode(req)) {
285
868
  return getWebAdapterUuid(req);
286
869
  }
287
- // Try serverless-express mode first
288
- const serverlessExpressUuid = getServerlessExpressUuid();
289
- if (serverlessExpressUuid) {
290
- return serverlessExpressUuid;
870
+ // Priority 2: Request has Lambda context attached (Jaypie adapter)
871
+ const requestContextUuid = getRequestContextUuid(req);
872
+ if (requestContextUuid) {
873
+ return requestContextUuid;
874
+ }
875
+ // Priority 3: Global context from Jaypie adapter
876
+ const jaypieAdapterUuid = getJaypieAdapterUuid();
877
+ if (jaypieAdapterUuid) {
878
+ return jaypieAdapterUuid;
291
879
  }
292
- // If no request but we might be in Web Adapter mode, try env var fallback
880
+ // Fallback: Web Adapter env var
293
881
  return getWebAdapterUuid();
294
882
  }
295
883
 
@@ -707,6 +1295,46 @@ function expressHandler(handlerOrOptions, optionsOrHandler) {
707
1295
  };
708
1296
  }
709
1297
 
1298
+ //
1299
+ //
1300
+ // Main
1301
+ //
1302
+ const httpHandler = (statusCode = HTTP.CODE.OK, context = {}) => {
1303
+ // Give a default name if there isn't one
1304
+ if (!context.name) {
1305
+ context.name = "_http";
1306
+ }
1307
+ // Return a function that will be used as an express route
1308
+ return expressHandler(async (req, res) => {
1309
+ // Map the most throwable status codes to errors and throw them!
1310
+ const error = {
1311
+ [HTTP.CODE.BAD_REQUEST]: BadRequestError,
1312
+ [HTTP.CODE.UNAUTHORIZED]: UnauthorizedError,
1313
+ [HTTP.CODE.FORBIDDEN]: ForbiddenError,
1314
+ [HTTP.CODE.NOT_FOUND]: NotFoundError,
1315
+ [HTTP.CODE.METHOD_NOT_ALLOWED]: MethodNotAllowedError,
1316
+ [HTTP.CODE.GONE]: GoneError,
1317
+ [HTTP.CODE.TEAPOT]: TeapotError,
1318
+ [HTTP.CODE.INTERNAL_ERROR]: InternalError,
1319
+ [HTTP.CODE.BAD_GATEWAY]: BadGatewayError,
1320
+ [HTTP.CODE.UNAVAILABLE]: UnavailableError,
1321
+ [HTTP.CODE.GATEWAY_TIMEOUT]: GatewayTimeoutError,
1322
+ };
1323
+ // If this maps to an error, throw it
1324
+ if (error[statusCode]) {
1325
+ log.trace(`@knowdev/express: gracefully throwing ${statusCode} up to projectHandler`);
1326
+ throw new error[statusCode]();
1327
+ }
1328
+ // If this is an error and we didn't get thrown, log a warning
1329
+ if (statusCode >= 400) {
1330
+ log.warn(`@knowdev/express: status code ${statusCode} not mapped as throwable`);
1331
+ }
1332
+ // Send the response
1333
+ res.status(statusCode);
1334
+ return statusCode === HTTP.CODE.NO_CONTENT ? null : {};
1335
+ }, context);
1336
+ };
1337
+
710
1338
  // Cast logger to extended interface for runtime features not in type definitions
711
1339
  const logger = log;
712
1340
  //
@@ -937,46 +1565,6 @@ function expressStreamHandler(handlerOrOptions, optionsOrHandler) {
937
1565
  };
938
1566
  }
939
1567
 
940
- //
941
- //
942
- // Main
943
- //
944
- const httpHandler = (statusCode = HTTP.CODE.OK, context = {}) => {
945
- // Give a default name if there isn't one
946
- if (!context.name) {
947
- context.name = "_http";
948
- }
949
- // Return a function that will be used as an express route
950
- return expressHandler(async (req, res) => {
951
- // Map the most throwable status codes to errors and throw them!
952
- const error = {
953
- [HTTP.CODE.BAD_REQUEST]: BadRequestError,
954
- [HTTP.CODE.UNAUTHORIZED]: UnauthorizedError,
955
- [HTTP.CODE.FORBIDDEN]: ForbiddenError,
956
- [HTTP.CODE.NOT_FOUND]: NotFoundError,
957
- [HTTP.CODE.METHOD_NOT_ALLOWED]: MethodNotAllowedError,
958
- [HTTP.CODE.GONE]: GoneError,
959
- [HTTP.CODE.TEAPOT]: TeapotError,
960
- [HTTP.CODE.INTERNAL_ERROR]: InternalError,
961
- [HTTP.CODE.BAD_GATEWAY]: BadGatewayError,
962
- [HTTP.CODE.UNAVAILABLE]: UnavailableError,
963
- [HTTP.CODE.GATEWAY_TIMEOUT]: GatewayTimeoutError,
964
- };
965
- // If this maps to an error, throw it
966
- if (error[statusCode]) {
967
- log.trace(`@knowdev/express: gracefully throwing ${statusCode} up to projectHandler`);
968
- throw new error[statusCode]();
969
- }
970
- // If this is an error and we didn't get thrown, log a warning
971
- if (statusCode >= 400) {
972
- log.warn(`@knowdev/express: status code ${statusCode} not mapped as throwable`);
973
- }
974
- // Send the response
975
- res.status(statusCode);
976
- return statusCode === HTTP.CODE.NO_CONTENT ? null : {};
977
- }, context);
978
- };
979
-
980
1568
  //
981
1569
  //
982
1570
  // Main
@@ -1030,5 +1618,5 @@ const noContentRoute = routes.noContentRoute;
1030
1618
  const notFoundRoute = routes.notFoundRoute;
1031
1619
  const notImplementedRoute = routes.notImplementedRoute;
1032
1620
 
1033
- export { EXPRESS, badRequestRoute, cors, createServer, echoRoute, expressHandler, httpHandler as expressHttpCodeHandler, expressStreamHandler, forbiddenRoute, getCurrentInvokeUuid, goneRoute, methodNotAllowedRoute, noContentRoute, notFoundRoute, notImplementedRoute };
1621
+ export { EXPRESS, LambdaRequest, LambdaResponseBuffered, LambdaResponseStreaming, badRequestRoute, cors, createLambdaHandler, createLambdaStreamHandler, createServer, echoRoute, expressHandler, httpHandler as expressHttpCodeHandler, expressStreamHandler, forbiddenRoute, getCurrentInvoke, getCurrentInvokeUuid, goneRoute, methodNotAllowedRoute, noContentRoute, notFoundRoute, notImplementedRoute };
1034
1622
  //# sourceMappingURL=index.js.map