@jaypie/express 1.2.3 → 1.2.4-rc1

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,618 @@
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
+ // Type Guards
83
+ //
84
+ /**
85
+ * Check if event is a Function URL / HTTP API v2 event.
86
+ */
87
+ function isFunctionUrlEvent(event) {
88
+ return "requestContext" in event && "http" in event.requestContext;
89
+ }
90
+ /**
91
+ * Check if event is an API Gateway REST API v1 event.
92
+ */
93
+ function isApiGatewayV1Event(event) {
94
+ return "httpMethod" in event;
95
+ }
96
+ //
97
+ //
98
+ // Factory Function
99
+ //
100
+ /**
101
+ * Create a LambdaRequest from a Lambda event (Function URL, HTTP API v2, or REST API v1).
102
+ */
103
+ function createLambdaRequest(event, context) {
104
+ let url;
105
+ let method;
106
+ let protocol;
107
+ let remoteAddress;
108
+ const headers = { ...event.headers };
109
+ if (isFunctionUrlEvent(event)) {
110
+ // Function URL / HTTP API v2 format
111
+ url = event.rawQueryString
112
+ ? `${event.rawPath}?${event.rawQueryString}`
113
+ : event.rawPath;
114
+ method = event.requestContext.http.method;
115
+ protocol = event.requestContext.http.protocol.split("/")[0].toLowerCase();
116
+ remoteAddress = event.requestContext.http.sourceIp;
117
+ // Normalize cookies into Cookie header if not already present
118
+ if (event.cookies && event.cookies.length > 0 && !headers.cookie) {
119
+ headers.cookie = event.cookies.join("; ");
120
+ }
121
+ }
122
+ else if (isApiGatewayV1Event(event)) {
123
+ // API Gateway REST API v1 format
124
+ const queryParams = event.queryStringParameters;
125
+ if (queryParams && Object.keys(queryParams).length > 0) {
126
+ const queryString = new URLSearchParams(queryParams).toString();
127
+ url = `${event.path}?${queryString}`;
128
+ }
129
+ else {
130
+ url = event.path;
131
+ }
132
+ method = event.httpMethod;
133
+ protocol = event.requestContext.protocol.split("/")[0].toLowerCase();
134
+ remoteAddress = event.requestContext.identity.sourceIp;
135
+ }
136
+ else {
137
+ throw new Error("Unsupported Lambda event format. Expected Function URL, HTTP API v2, or REST API v1 event.");
138
+ }
139
+ // Decode body if present
140
+ let body = null;
141
+ if (event.body) {
142
+ body = event.isBase64Encoded
143
+ ? Buffer.from(event.body, "base64")
144
+ : Buffer.from(event.body, "utf8");
145
+ }
146
+ return new LambdaRequest({
147
+ body,
148
+ headers,
149
+ lambdaContext: context,
150
+ lambdaEvent: event,
151
+ method,
152
+ protocol,
153
+ remoteAddress,
154
+ url,
155
+ });
156
+ }
157
+
158
+ //
159
+ //
160
+ // Constants
161
+ //
162
+ const BINARY_CONTENT_TYPE_PATTERNS = [
163
+ /^application\/octet-stream$/,
164
+ /^application\/pdf$/,
165
+ /^application\/zip$/,
166
+ /^audio\//,
167
+ /^font\//,
168
+ /^image\//,
169
+ /^video\//,
170
+ ];
171
+ //
172
+ //
173
+ // LambdaResponseBuffered Class
174
+ //
175
+ /**
176
+ * Mock ServerResponse that buffers the response.
177
+ * Collects status, headers, and body chunks, then returns a Lambda response.
178
+ */
179
+ class LambdaResponseBuffered extends Writable {
180
+ constructor() {
181
+ super();
182
+ this.statusCode = 200;
183
+ this.statusMessage = "OK";
184
+ // Mock socket to satisfy Express/finalhandler checks
185
+ this.socket = {
186
+ remoteAddress: "127.0.0.1",
187
+ };
188
+ this._chunks = [];
189
+ this._headers = new Map();
190
+ this._headersSent = false;
191
+ this._resolve = null;
192
+ }
193
+ //
194
+ // Promise-based API for getting final result
195
+ //
196
+ getResult() {
197
+ return new Promise((resolve) => {
198
+ if (this.writableEnded) {
199
+ resolve(this.buildResult());
200
+ }
201
+ else {
202
+ this._resolve = resolve;
203
+ }
204
+ });
205
+ }
206
+ //
207
+ // Header management
208
+ //
209
+ setHeader(name, value) {
210
+ if (this._headersSent) {
211
+ // In production, log warning but don't throw to match Express behavior
212
+ return this;
213
+ }
214
+ this._headers.set(name.toLowerCase(), String(value));
215
+ return this;
216
+ }
217
+ getHeader(name) {
218
+ return this._headers.get(name.toLowerCase());
219
+ }
220
+ removeHeader(name) {
221
+ this._headers.delete(name.toLowerCase());
222
+ }
223
+ getHeaders() {
224
+ const headers = {};
225
+ for (const [key, value] of this._headers) {
226
+ headers[key] = value;
227
+ }
228
+ return headers;
229
+ }
230
+ hasHeader(name) {
231
+ return this._headers.has(name.toLowerCase());
232
+ }
233
+ getHeaderNames() {
234
+ return Array.from(this._headers.keys());
235
+ }
236
+ writeHead(statusCode, statusMessageOrHeaders, headers) {
237
+ this.statusCode = statusCode;
238
+ let headersToSet;
239
+ if (typeof statusMessageOrHeaders === "string") {
240
+ this.statusMessage = statusMessageOrHeaders;
241
+ headersToSet = headers;
242
+ }
243
+ else if (statusMessageOrHeaders &&
244
+ typeof statusMessageOrHeaders === "object") {
245
+ headersToSet = statusMessageOrHeaders;
246
+ }
247
+ if (headersToSet) {
248
+ for (const [key, value] of Object.entries(headersToSet)) {
249
+ if (value !== undefined) {
250
+ this.setHeader(key, value);
251
+ }
252
+ }
253
+ }
254
+ this._headersSent = true;
255
+ return this;
256
+ }
257
+ get headersSent() {
258
+ return this._headersSent;
259
+ }
260
+ //
261
+ // Express compatibility methods
262
+ //
263
+ status(code) {
264
+ this.statusCode = code;
265
+ return this;
266
+ }
267
+ json(data) {
268
+ this.setHeader("content-type", "application/json");
269
+ this.end(JSON.stringify(data));
270
+ return this;
271
+ }
272
+ send(body) {
273
+ if (typeof body === "object" && !Buffer.isBuffer(body)) {
274
+ return this.json(body);
275
+ }
276
+ this.end(body);
277
+ return this;
278
+ }
279
+ //
280
+ // Writable stream implementation
281
+ //
282
+ _write(chunk, encoding, // eslint-disable-line no-undef
283
+ callback) {
284
+ const buffer = Buffer.isBuffer(chunk)
285
+ ? chunk
286
+ : Buffer.from(chunk, encoding);
287
+ this._chunks.push(buffer);
288
+ this._headersSent = true;
289
+ callback();
290
+ }
291
+ _final(callback) {
292
+ if (this._resolve) {
293
+ this._resolve(this.buildResult());
294
+ }
295
+ callback();
296
+ }
297
+ //
298
+ // Private helpers
299
+ //
300
+ buildResult() {
301
+ const body = Buffer.concat(this._chunks);
302
+ const contentType = this.getHeader("content-type") || "";
303
+ // Determine if response should be base64 encoded
304
+ const isBase64Encoded = this.isBinaryContentType(contentType);
305
+ // Build headers object
306
+ const headers = {};
307
+ const cookies = [];
308
+ for (const [key, value] of this._headers) {
309
+ if (key === "set-cookie") {
310
+ // Collect Set-Cookie headers for v2 response format
311
+ if (Array.isArray(value)) {
312
+ cookies.push(...value);
313
+ }
314
+ else {
315
+ cookies.push(value);
316
+ }
317
+ }
318
+ else {
319
+ headers[key] = Array.isArray(value) ? value.join(", ") : String(value);
320
+ }
321
+ }
322
+ const result = {
323
+ body: isBase64Encoded ? body.toString("base64") : body.toString("utf8"),
324
+ headers,
325
+ isBase64Encoded,
326
+ statusCode: this.statusCode,
327
+ };
328
+ // Only include cookies if present (v2 format)
329
+ if (cookies.length > 0) {
330
+ result.cookies = cookies;
331
+ }
332
+ return result;
333
+ }
334
+ isBinaryContentType(contentType) {
335
+ return BINARY_CONTENT_TYPE_PATTERNS.some((pattern) => pattern.test(contentType));
336
+ }
337
+ }
338
+
339
+ //
340
+ //
341
+ // LambdaResponseStreaming Class
342
+ //
343
+ /**
344
+ * Mock ServerResponse that streams directly to Lambda responseStream.
345
+ * Uses awslambda.HttpResponseStream.from() to set status and headers.
346
+ */
347
+ class LambdaResponseStreaming extends Writable {
348
+ constructor(responseStream) {
349
+ super();
350
+ this.statusCode = 200;
351
+ this.statusMessage = "OK";
352
+ // Mock socket to satisfy Express/finalhandler checks
353
+ this.socket = {
354
+ remoteAddress: "127.0.0.1",
355
+ };
356
+ this._headers = new Map();
357
+ this._headersSent = false;
358
+ this._pendingWrites = [];
359
+ this._wrappedStream = null;
360
+ this._responseStream = responseStream;
361
+ }
362
+ //
363
+ // Header management
364
+ //
365
+ setHeader(name, value) {
366
+ if (this._headersSent) {
367
+ // In streaming mode, log warning but don't throw
368
+ // Headers cannot be changed after body starts
369
+ return this;
370
+ }
371
+ this._headers.set(name.toLowerCase(), String(value));
372
+ return this;
373
+ }
374
+ getHeader(name) {
375
+ return this._headers.get(name.toLowerCase());
376
+ }
377
+ removeHeader(name) {
378
+ if (!this._headersSent) {
379
+ this._headers.delete(name.toLowerCase());
380
+ }
381
+ }
382
+ getHeaders() {
383
+ const headers = {};
384
+ for (const [key, value] of this._headers) {
385
+ headers[key] = value;
386
+ }
387
+ return headers;
388
+ }
389
+ hasHeader(name) {
390
+ return this._headers.has(name.toLowerCase());
391
+ }
392
+ getHeaderNames() {
393
+ return Array.from(this._headers.keys());
394
+ }
395
+ writeHead(statusCode, statusMessageOrHeaders, headers) {
396
+ if (this._headersSent) {
397
+ return this;
398
+ }
399
+ this.statusCode = statusCode;
400
+ let headersToSet;
401
+ if (typeof statusMessageOrHeaders === "string") {
402
+ this.statusMessage = statusMessageOrHeaders;
403
+ headersToSet = headers;
404
+ }
405
+ else if (statusMessageOrHeaders &&
406
+ typeof statusMessageOrHeaders === "object") {
407
+ headersToSet = statusMessageOrHeaders;
408
+ }
409
+ if (headersToSet) {
410
+ for (const [key, value] of Object.entries(headersToSet)) {
411
+ if (value !== undefined) {
412
+ this.setHeader(key, value);
413
+ }
414
+ }
415
+ }
416
+ this.flushHeaders();
417
+ return this;
418
+ }
419
+ get headersSent() {
420
+ return this._headersSent;
421
+ }
422
+ flushHeaders() {
423
+ if (this._headersSent)
424
+ return;
425
+ const headers = {};
426
+ for (const [key, value] of this._headers) {
427
+ headers[key] = Array.isArray(value) ? value.join(", ") : String(value);
428
+ }
429
+ const metadata = {
430
+ headers,
431
+ statusCode: this.statusCode,
432
+ };
433
+ // Wrap the stream with metadata using awslambda global
434
+ this._wrappedStream = awslambda.HttpResponseStream.from(this._responseStream, metadata);
435
+ this._headersSent = true;
436
+ // Flush pending writes
437
+ for (const { callback, chunk } of this._pendingWrites) {
438
+ this._wrappedStream.write(chunk);
439
+ callback();
440
+ }
441
+ this._pendingWrites = [];
442
+ }
443
+ //
444
+ // Express compatibility methods
445
+ //
446
+ status(code) {
447
+ this.statusCode = code;
448
+ return this;
449
+ }
450
+ json(data) {
451
+ this.setHeader("content-type", "application/json");
452
+ this.end(JSON.stringify(data));
453
+ return this;
454
+ }
455
+ send(body) {
456
+ if (typeof body === "object" && !Buffer.isBuffer(body)) {
457
+ return this.json(body);
458
+ }
459
+ this.end(body);
460
+ return this;
461
+ }
462
+ //
463
+ // Writable stream implementation
464
+ //
465
+ _write(chunk, encoding, // eslint-disable-line no-undef
466
+ callback) {
467
+ const buffer = Buffer.isBuffer(chunk)
468
+ ? chunk
469
+ : Buffer.from(chunk, encoding);
470
+ if (!this._headersSent) {
471
+ // Buffer writes until headers are sent
472
+ this._pendingWrites.push({ callback: () => callback(), chunk: buffer });
473
+ // Auto-flush headers on first write
474
+ this.flushHeaders();
475
+ }
476
+ else {
477
+ this._wrappedStream.write(buffer);
478
+ callback();
479
+ }
480
+ }
481
+ _final(callback) {
482
+ if (!this._headersSent) {
483
+ this.flushHeaders();
484
+ }
485
+ this._wrappedStream?.end();
486
+ callback();
487
+ }
488
+ }
489
+
490
+ //
491
+ //
492
+ // Current Invoke Context
493
+ //
494
+ let currentInvoke = null;
495
+ /**
496
+ * Get the current Lambda invoke context.
497
+ * Used by getCurrentInvokeUuid adapter to get the request ID.
498
+ */
499
+ function getCurrentInvoke() {
500
+ return currentInvoke;
501
+ }
502
+ /**
503
+ * Set the current Lambda invoke context.
504
+ * Called at the start of each Lambda invocation.
505
+ */
506
+ function setCurrentInvoke(event, context) {
507
+ currentInvoke = { context, event };
508
+ }
509
+ /**
510
+ * Clear the current Lambda invoke context.
511
+ * Called at the end of each Lambda invocation.
512
+ */
513
+ function clearCurrentInvoke() {
514
+ currentInvoke = null;
515
+ }
516
+ //
517
+ //
518
+ // Express App Runner
519
+ //
520
+ /**
521
+ * Run Express app with mock request/response.
522
+ * Returns a promise that resolves when the response is complete.
523
+ */
524
+ function runExpressApp(app, req, res) {
525
+ return new Promise((resolve, reject) => {
526
+ // Listen for response completion
527
+ res.on("finish", resolve);
528
+ res.on("error", reject);
529
+ // Run the Express app
530
+ // Cast to Express types since our mocks implement the required interface
531
+ app(req, res);
532
+ });
533
+ }
534
+ //
535
+ //
536
+ // Buffered Handler Factory
537
+ //
538
+ /**
539
+ * Create a Lambda handler that buffers the Express response.
540
+ * Returns the complete response as a Lambda response object.
541
+ *
542
+ * @example
543
+ * ```typescript
544
+ * import express from "express";
545
+ * import { createLambdaHandler } from "@jaypie/express";
546
+ *
547
+ * const app = express();
548
+ * app.get("/", (req, res) => res.json({ message: "Hello" }));
549
+ *
550
+ * export const handler = createLambdaHandler(app);
551
+ * ```
552
+ */
553
+ function createLambdaHandler(app, _options) {
554
+ return async (event, context) => {
555
+ try {
556
+ // Set current invoke for getCurrentInvokeUuid
557
+ setCurrentInvoke(event, context);
558
+ // Create mock request from Lambda event
559
+ const req = createLambdaRequest(event, context);
560
+ // Create buffered response collector
561
+ const res = new LambdaResponseBuffered();
562
+ // Run Express app
563
+ await runExpressApp(app, req, res);
564
+ // Return Lambda response
565
+ return res.getResult();
566
+ }
567
+ finally {
568
+ // Clear current invoke context
569
+ clearCurrentInvoke();
570
+ }
571
+ };
572
+ }
573
+ //
574
+ //
575
+ // Streaming Handler Factory
576
+ //
577
+ /**
578
+ * Create a Lambda handler that streams the Express response.
579
+ * Uses awslambda.streamifyResponse() for Lambda response streaming.
580
+ *
581
+ * @example
582
+ * ```typescript
583
+ * import express from "express";
584
+ * import { createLambdaStreamHandler } from "@jaypie/express";
585
+ *
586
+ * const app = express();
587
+ * app.get("/stream", (req, res) => {
588
+ * res.setHeader("Content-Type", "text/event-stream");
589
+ * res.write("data: Hello\n\n");
590
+ * res.end();
591
+ * });
592
+ *
593
+ * export const handler = createLambdaStreamHandler(app);
594
+ * ```
595
+ */
596
+ function createLambdaStreamHandler(app, _options) {
597
+ // Wrap with awslambda.streamifyResponse for Lambda streaming
598
+ // @ts-expect-error awslambda is a Lambda runtime global
599
+ return awslambda.streamifyResponse(async (event, responseStream, context) => {
600
+ try {
601
+ // Set current invoke for getCurrentInvokeUuid
602
+ setCurrentInvoke(event, context);
603
+ // Create mock request from Lambda event
604
+ const req = createLambdaRequest(event, context);
605
+ // Create streaming response that pipes to Lambda responseStream
606
+ const res = new LambdaResponseStreaming(responseStream);
607
+ // Run Express app
608
+ await runExpressApp(app, req, res);
609
+ }
610
+ finally {
611
+ // Clear current invoke context
612
+ clearCurrentInvoke();
613
+ }
614
+ });
615
+ }
8
616
 
9
617
  //
10
618
  //
@@ -256,40 +864,54 @@ function isWebAdapterMode(req) {
256
864
  return false;
257
865
  }
258
866
  /**
259
- * Adapter for the "@codegenie/serverless-express" uuid
867
+ * Get UUID from Jaypie Lambda adapter context.
868
+ * This is set by createLambdaHandler/createLambdaStreamHandler.
260
869
  */
261
- function getServerlessExpressUuid() {
870
+ function getJaypieAdapterUuid() {
262
871
  const currentInvoke = getCurrentInvoke();
263
- if (currentInvoke &&
264
- currentInvoke.context &&
265
- currentInvoke.context.awsRequestId) {
872
+ if (currentInvoke?.context?.awsRequestId) {
266
873
  return currentInvoke.context.awsRequestId;
267
874
  }
268
875
  return undefined;
269
876
  }
877
+ /**
878
+ * Get UUID from request object if it has Lambda context attached.
879
+ * The Jaypie adapter attaches _lambdaContext to the request.
880
+ */
881
+ function getRequestContextUuid(req) {
882
+ if (req && req._lambdaContext?.awsRequestId) {
883
+ return req._lambdaContext.awsRequestId;
884
+ }
885
+ return undefined;
886
+ }
270
887
  //
271
888
  //
272
889
  // Main
273
890
  //
274
891
  /**
275
892
  * Get the current invoke UUID from Lambda context.
276
- * Works in both serverless-express mode and Lambda Web Adapter mode.
893
+ * Works with Jaypie Lambda adapter and Lambda Web Adapter mode.
277
894
  *
278
- * @param req - Optional Express request object. Required for Web Adapter mode
279
- * to extract the x-amzn-request-id header.
895
+ * @param req - Optional Express request object. Used to extract context
896
+ * from Web Adapter headers or Jaypie adapter's _lambdaContext.
280
897
  * @returns The AWS request ID or undefined if not in Lambda context
281
898
  */
282
899
  function getCurrentInvokeUuid(req) {
283
- // If request is provided and has Web Adapter header, use Web Adapter mode
900
+ // Priority 1: Web Adapter mode (header-based)
284
901
  if (isWebAdapterMode(req)) {
285
902
  return getWebAdapterUuid(req);
286
903
  }
287
- // Try serverless-express mode first
288
- const serverlessExpressUuid = getServerlessExpressUuid();
289
- if (serverlessExpressUuid) {
290
- return serverlessExpressUuid;
904
+ // Priority 2: Request has Lambda context attached (Jaypie adapter)
905
+ const requestContextUuid = getRequestContextUuid(req);
906
+ if (requestContextUuid) {
907
+ return requestContextUuid;
908
+ }
909
+ // Priority 3: Global context from Jaypie adapter
910
+ const jaypieAdapterUuid = getJaypieAdapterUuid();
911
+ if (jaypieAdapterUuid) {
912
+ return jaypieAdapterUuid;
291
913
  }
292
- // If no request but we might be in Web Adapter mode, try env var fallback
914
+ // Fallback: Web Adapter env var
293
915
  return getWebAdapterUuid();
294
916
  }
295
917
 
@@ -707,6 +1329,46 @@ function expressHandler(handlerOrOptions, optionsOrHandler) {
707
1329
  };
708
1330
  }
709
1331
 
1332
+ //
1333
+ //
1334
+ // Main
1335
+ //
1336
+ const httpHandler = (statusCode = HTTP.CODE.OK, context = {}) => {
1337
+ // Give a default name if there isn't one
1338
+ if (!context.name) {
1339
+ context.name = "_http";
1340
+ }
1341
+ // Return a function that will be used as an express route
1342
+ return expressHandler(async (req, res) => {
1343
+ // Map the most throwable status codes to errors and throw them!
1344
+ const error = {
1345
+ [HTTP.CODE.BAD_REQUEST]: BadRequestError,
1346
+ [HTTP.CODE.UNAUTHORIZED]: UnauthorizedError,
1347
+ [HTTP.CODE.FORBIDDEN]: ForbiddenError,
1348
+ [HTTP.CODE.NOT_FOUND]: NotFoundError,
1349
+ [HTTP.CODE.METHOD_NOT_ALLOWED]: MethodNotAllowedError,
1350
+ [HTTP.CODE.GONE]: GoneError,
1351
+ [HTTP.CODE.TEAPOT]: TeapotError,
1352
+ [HTTP.CODE.INTERNAL_ERROR]: InternalError,
1353
+ [HTTP.CODE.BAD_GATEWAY]: BadGatewayError,
1354
+ [HTTP.CODE.UNAVAILABLE]: UnavailableError,
1355
+ [HTTP.CODE.GATEWAY_TIMEOUT]: GatewayTimeoutError,
1356
+ };
1357
+ // If this maps to an error, throw it
1358
+ if (error[statusCode]) {
1359
+ log.trace(`@knowdev/express: gracefully throwing ${statusCode} up to projectHandler`);
1360
+ throw new error[statusCode]();
1361
+ }
1362
+ // If this is an error and we didn't get thrown, log a warning
1363
+ if (statusCode >= 400) {
1364
+ log.warn(`@knowdev/express: status code ${statusCode} not mapped as throwable`);
1365
+ }
1366
+ // Send the response
1367
+ res.status(statusCode);
1368
+ return statusCode === HTTP.CODE.NO_CONTENT ? null : {};
1369
+ }, context);
1370
+ };
1371
+
710
1372
  // Cast logger to extended interface for runtime features not in type definitions
711
1373
  const logger = log;
712
1374
  //
@@ -937,46 +1599,6 @@ function expressStreamHandler(handlerOrOptions, optionsOrHandler) {
937
1599
  };
938
1600
  }
939
1601
 
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
1602
  //
981
1603
  //
982
1604
  // Main
@@ -1030,5 +1652,5 @@ const noContentRoute = routes.noContentRoute;
1030
1652
  const notFoundRoute = routes.notFoundRoute;
1031
1653
  const notImplementedRoute = routes.notImplementedRoute;
1032
1654
 
1033
- export { EXPRESS, badRequestRoute, cors, createServer, echoRoute, expressHandler, httpHandler as expressHttpCodeHandler, expressStreamHandler, forbiddenRoute, getCurrentInvokeUuid, goneRoute, methodNotAllowedRoute, noContentRoute, notFoundRoute, notImplementedRoute };
1655
+ 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
1656
  //# sourceMappingURL=index.js.map