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