@jaypie/express 1.2.4-rc8 → 1.2.4
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/cjs/adapter/LambdaResponseBuffered.d.ts +13 -5
- package/dist/cjs/adapter/LambdaResponseStreaming.d.ts +8 -2
- package/dist/cjs/adapter/__tests__/debug-harness.d.ts +1 -0
- package/dist/cjs/expressStreamHandler.d.ts +2 -0
- package/dist/cjs/getCurrentInvokeUuid.adapter.d.ts +2 -2
- package/dist/cjs/index.cjs +322 -215
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.ts +0 -2
- package/dist/esm/adapter/LambdaResponseBuffered.d.ts +13 -5
- package/dist/esm/adapter/LambdaResponseStreaming.d.ts +8 -2
- package/dist/esm/adapter/__tests__/debug-harness.d.ts +1 -0
- package/dist/esm/expressStreamHandler.d.ts +2 -0
- package/dist/esm/getCurrentInvokeUuid.adapter.d.ts +2 -2
- package/dist/esm/index.d.ts +0 -2
- package/dist/esm/index.js +322 -214
- package/dist/esm/index.js.map +1 -1
- package/package.json +12 -16
- package/dist/cjs/createServer.d.ts +0 -60
- package/dist/cjs/getCurrentInvokeUuid.webadapter.d.ts +0 -12
- package/dist/esm/createServer.d.ts +0 -60
- package/dist/esm/getCurrentInvokeUuid.webadapter.d.ts +0 -12
package/dist/esm/index.js
CHANGED
|
@@ -3,8 +3,8 @@ import { ServerResponse } from 'node:http';
|
|
|
3
3
|
import { CorsError, BadRequestError, UnhandledError, GatewayTimeoutError, UnavailableError, BadGatewayError, InternalError, TeapotError, GoneError, MethodNotAllowedError, NotFoundError, ForbiddenError, UnauthorizedError, NotImplementedError } from '@jaypie/errors';
|
|
4
4
|
import { force, envBoolean, JAYPIE, HTTP, getHeaderFrom, jaypieHandler } from '@jaypie/kit';
|
|
5
5
|
import expressCors from 'cors';
|
|
6
|
+
import { loadEnvSecrets, getContentTypeForFormat, formatStreamError } from '@jaypie/aws';
|
|
6
7
|
import { log } from '@jaypie/logger';
|
|
7
|
-
import { loadEnvSecrets } from '@jaypie/aws';
|
|
8
8
|
import { hasDatadogEnv, submitMetric, DATADOG } from '@jaypie/datadog';
|
|
9
9
|
|
|
10
10
|
//
|
|
@@ -32,6 +32,15 @@ class LambdaRequest extends Readable {
|
|
|
32
32
|
this.path = options.url.split("?")[0];
|
|
33
33
|
this.headers = this.normalizeHeaders(options.headers);
|
|
34
34
|
this.bodyBuffer = options.body ?? null;
|
|
35
|
+
// Parse query string from URL
|
|
36
|
+
const queryIndex = options.url.indexOf("?");
|
|
37
|
+
if (queryIndex !== -1) {
|
|
38
|
+
const queryString = options.url.slice(queryIndex + 1);
|
|
39
|
+
const params = new URLSearchParams(queryString);
|
|
40
|
+
for (const [key, value] of params) {
|
|
41
|
+
this.query[key] = value;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
35
44
|
// Store Lambda context
|
|
36
45
|
this._lambdaContext = options.lambdaContext;
|
|
37
46
|
this._lambdaEvent = options.lambdaEvent;
|
|
@@ -42,6 +51,18 @@ class LambdaRequest extends Readable {
|
|
|
42
51
|
remoteAddress: options.remoteAddress,
|
|
43
52
|
};
|
|
44
53
|
this.connection = this.socket;
|
|
54
|
+
// Schedule body push for next tick to ensure stream is ready
|
|
55
|
+
// This is needed for body parsers that consume the stream
|
|
56
|
+
if (this.bodyBuffer && this.bodyBuffer.length > 0) {
|
|
57
|
+
process.nextTick(() => {
|
|
58
|
+
if (!this.bodyPushed) {
|
|
59
|
+
this.push(this.bodyBuffer);
|
|
60
|
+
this.push(null);
|
|
61
|
+
this.bodyPushed = true;
|
|
62
|
+
this.complete = true;
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
45
66
|
}
|
|
46
67
|
//
|
|
47
68
|
// Readable stream implementation
|
|
@@ -143,6 +164,11 @@ function createLambdaRequest(event, context) {
|
|
|
143
164
|
body = event.isBase64Encoded
|
|
144
165
|
? Buffer.from(event.body, "base64")
|
|
145
166
|
: Buffer.from(event.body, "utf8");
|
|
167
|
+
// Add content-length header if not present (required for body parsers)
|
|
168
|
+
const hasContentLength = Object.keys(headers).some((k) => k.toLowerCase() === "content-length");
|
|
169
|
+
if (!hasContentLength) {
|
|
170
|
+
headers["content-length"] = String(body.length);
|
|
171
|
+
}
|
|
146
172
|
}
|
|
147
173
|
return new LambdaRequest({
|
|
148
174
|
body,
|
|
@@ -160,6 +186,9 @@ function createLambdaRequest(event, context) {
|
|
|
160
186
|
//
|
|
161
187
|
// Constants
|
|
162
188
|
//
|
|
189
|
+
// Symbol to identify Lambda mock responses. Uses Symbol.for() to ensure
|
|
190
|
+
// the same symbol is used across bundles/realms. Survives prototype manipulation.
|
|
191
|
+
const JAYPIE_LAMBDA_MOCK = Symbol.for("@jaypie/express/LambdaMock");
|
|
163
192
|
// Get Node's internal kOutHeaders symbol from ServerResponse prototype.
|
|
164
193
|
// This is needed for compatibility with Datadog dd-trace instrumentation,
|
|
165
194
|
// which patches HTTP methods and expects this internal state to exist.
|
|
@@ -190,22 +219,90 @@ class LambdaResponseBuffered extends Writable {
|
|
|
190
219
|
this.socket = {
|
|
191
220
|
remoteAddress: "127.0.0.1",
|
|
192
221
|
};
|
|
222
|
+
// Internal state exposed for direct manipulation by safe response methods
|
|
223
|
+
// that need to bypass dd-trace interception of stream methods
|
|
193
224
|
this._chunks = [];
|
|
225
|
+
this._ended = false; // Track ended state since writableEnded is lost after prototype change
|
|
194
226
|
this._headers = new Map();
|
|
195
227
|
this._headersSent = false;
|
|
196
228
|
this._resolve = null;
|
|
229
|
+
// Mark as Lambda mock response for identification in expressHandler
|
|
230
|
+
this[JAYPIE_LAMBDA_MOCK] = true;
|
|
197
231
|
// Initialize Node's internal kOutHeaders for dd-trace compatibility.
|
|
198
232
|
// dd-trace patches HTTP methods and expects this internal state.
|
|
199
233
|
if (kOutHeaders$1) {
|
|
200
234
|
this[kOutHeaders$1] = Object.create(null);
|
|
201
235
|
}
|
|
236
|
+
// CRITICAL: Define key methods as instance properties to survive Express's
|
|
237
|
+
// setPrototypeOf(res, app.response) in middleware/init.js which would
|
|
238
|
+
// otherwise replace our prototype with ServerResponse.prototype.
|
|
239
|
+
// Instance properties take precedence over prototype properties.
|
|
240
|
+
this.getHeader = this.getHeader.bind(this);
|
|
241
|
+
this.setHeader = this.setHeader.bind(this);
|
|
242
|
+
this.removeHeader = this.removeHeader.bind(this);
|
|
243
|
+
this.hasHeader = this.hasHeader.bind(this);
|
|
244
|
+
this.getHeaders = this.getHeaders.bind(this);
|
|
245
|
+
this.getHeaderNames = this.getHeaderNames.bind(this);
|
|
246
|
+
this.writeHead = this.writeHead.bind(this);
|
|
247
|
+
this.get = this.get.bind(this);
|
|
248
|
+
this.set = this.set.bind(this);
|
|
249
|
+
this.status = this.status.bind(this);
|
|
250
|
+
this.json = this.json.bind(this);
|
|
251
|
+
this.send = this.send.bind(this);
|
|
252
|
+
this.vary = this.vary.bind(this);
|
|
253
|
+
this.end = this.end.bind(this);
|
|
254
|
+
this.write = this.write.bind(this);
|
|
255
|
+
// Also bind internal Writable methods that are called via prototype chain
|
|
256
|
+
this._write = this._write.bind(this);
|
|
257
|
+
this._final = this._final.bind(this);
|
|
258
|
+
// Bind result-building methods
|
|
259
|
+
this.getResult = this.getResult.bind(this);
|
|
260
|
+
this.buildResult = this.buildResult.bind(this);
|
|
261
|
+
this.isBinaryContentType = this.isBinaryContentType.bind(this);
|
|
262
|
+
}
|
|
263
|
+
//
|
|
264
|
+
// Internal bypass methods - completely avoid prototype chain lookup
|
|
265
|
+
// These directly access _headers Map, safe from dd-trace interception
|
|
266
|
+
//
|
|
267
|
+
_internalGetHeader(name) {
|
|
268
|
+
const value = this._headers.get(name.toLowerCase());
|
|
269
|
+
return value ? String(value) : undefined;
|
|
270
|
+
}
|
|
271
|
+
_internalSetHeader(name, value) {
|
|
272
|
+
if (!this._headersSent) {
|
|
273
|
+
const lowerName = name.toLowerCase();
|
|
274
|
+
this._headers.set(lowerName, value);
|
|
275
|
+
// Also sync kOutHeaders for any code that expects it
|
|
276
|
+
if (kOutHeaders$1) {
|
|
277
|
+
const outHeaders = this[kOutHeaders$1];
|
|
278
|
+
if (outHeaders) {
|
|
279
|
+
outHeaders[lowerName] = [name, value];
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
_internalHasHeader(name) {
|
|
285
|
+
return this._headers.has(name.toLowerCase());
|
|
286
|
+
}
|
|
287
|
+
_internalRemoveHeader(name) {
|
|
288
|
+
if (!this._headersSent) {
|
|
289
|
+
const lowerName = name.toLowerCase();
|
|
290
|
+
this._headers.delete(lowerName);
|
|
291
|
+
if (kOutHeaders$1) {
|
|
292
|
+
const outHeaders = this[kOutHeaders$1];
|
|
293
|
+
if (outHeaders) {
|
|
294
|
+
delete outHeaders[lowerName];
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
202
298
|
}
|
|
203
299
|
//
|
|
204
300
|
// Promise-based API for getting final result
|
|
205
301
|
//
|
|
206
302
|
getResult() {
|
|
207
303
|
return new Promise((resolve) => {
|
|
208
|
-
|
|
304
|
+
// Use _ended instead of writableEnded since Express's setPrototypeOf breaks the getter
|
|
305
|
+
if (this._ended) {
|
|
209
306
|
resolve(this.buildResult());
|
|
210
307
|
}
|
|
211
308
|
else {
|
|
@@ -263,36 +360,40 @@ class LambdaResponseBuffered extends Writable {
|
|
|
263
360
|
/**
|
|
264
361
|
* Proxy for direct header access (e.g., res.headers['content-type']).
|
|
265
362
|
* Required for compatibility with middleware like helmet that access headers directly.
|
|
363
|
+
* Uses direct _headers access to bypass dd-trace interception.
|
|
266
364
|
*/
|
|
267
365
|
get headers() {
|
|
268
366
|
return new Proxy({}, {
|
|
269
367
|
deleteProperty: (_target, prop) => {
|
|
270
|
-
this.
|
|
368
|
+
this._headers.delete(String(prop).toLowerCase());
|
|
271
369
|
return true;
|
|
272
370
|
},
|
|
273
371
|
get: (_target, prop) => {
|
|
274
372
|
if (typeof prop === "symbol")
|
|
275
373
|
return undefined;
|
|
276
|
-
return this.
|
|
374
|
+
return this._headers.get(String(prop).toLowerCase());
|
|
277
375
|
},
|
|
278
376
|
getOwnPropertyDescriptor: (_target, prop) => {
|
|
279
|
-
|
|
377
|
+
const lowerProp = String(prop).toLowerCase();
|
|
378
|
+
if (this._headers.has(lowerProp)) {
|
|
280
379
|
return {
|
|
281
380
|
configurable: true,
|
|
282
381
|
enumerable: true,
|
|
283
|
-
value: this.
|
|
382
|
+
value: this._headers.get(lowerProp),
|
|
284
383
|
};
|
|
285
384
|
}
|
|
286
385
|
return undefined;
|
|
287
386
|
},
|
|
288
387
|
has: (_target, prop) => {
|
|
289
|
-
return this.
|
|
388
|
+
return this._headers.has(String(prop).toLowerCase());
|
|
290
389
|
},
|
|
291
390
|
ownKeys: () => {
|
|
292
|
-
return this.
|
|
391
|
+
return Array.from(this._headers.keys());
|
|
293
392
|
},
|
|
294
393
|
set: (_target, prop, value) => {
|
|
295
|
-
this.
|
|
394
|
+
if (!this._headersSent) {
|
|
395
|
+
this._headers.set(String(prop).toLowerCase(), value);
|
|
396
|
+
}
|
|
296
397
|
return true;
|
|
297
398
|
},
|
|
298
399
|
});
|
|
@@ -309,9 +410,10 @@ class LambdaResponseBuffered extends Writable {
|
|
|
309
410
|
headersToSet = statusMessageOrHeaders;
|
|
310
411
|
}
|
|
311
412
|
if (headersToSet) {
|
|
413
|
+
// Use direct _headers access to bypass dd-trace interception
|
|
312
414
|
for (const [key, value] of Object.entries(headersToSet)) {
|
|
313
415
|
if (value !== undefined) {
|
|
314
|
-
this.
|
|
416
|
+
this._headers.set(key.toLowerCase(), String(value));
|
|
315
417
|
}
|
|
316
418
|
}
|
|
317
419
|
}
|
|
@@ -348,7 +450,8 @@ class LambdaResponseBuffered extends Writable {
|
|
|
348
450
|
return this;
|
|
349
451
|
}
|
|
350
452
|
json(data) {
|
|
351
|
-
|
|
453
|
+
// Use direct _headers access to bypass dd-trace interception
|
|
454
|
+
this._headers.set("content-type", "application/json");
|
|
352
455
|
this.end(JSON.stringify(data));
|
|
353
456
|
return this;
|
|
354
457
|
}
|
|
@@ -362,11 +465,12 @@ class LambdaResponseBuffered extends Writable {
|
|
|
362
465
|
/**
|
|
363
466
|
* Add a field to the Vary response header.
|
|
364
467
|
* Used by CORS middleware to indicate response varies by Origin.
|
|
468
|
+
* Uses direct _headers access to bypass dd-trace interception.
|
|
365
469
|
*/
|
|
366
470
|
vary(field) {
|
|
367
|
-
const existing = this.
|
|
471
|
+
const existing = this._headers.get("vary");
|
|
368
472
|
if (!existing) {
|
|
369
|
-
this.
|
|
473
|
+
this._headers.set("vary", field);
|
|
370
474
|
}
|
|
371
475
|
else {
|
|
372
476
|
// Append to existing Vary header if field not already present
|
|
@@ -374,7 +478,7 @@ class LambdaResponseBuffered extends Writable {
|
|
|
374
478
|
.split(",")
|
|
375
479
|
.map((f) => f.trim().toLowerCase());
|
|
376
480
|
if (!fields.includes(field.toLowerCase())) {
|
|
377
|
-
this.
|
|
481
|
+
this._headers.set("vary", `${existing}, ${field}`);
|
|
378
482
|
}
|
|
379
483
|
}
|
|
380
484
|
return this;
|
|
@@ -392,6 +496,7 @@ class LambdaResponseBuffered extends Writable {
|
|
|
392
496
|
callback();
|
|
393
497
|
}
|
|
394
498
|
_final(callback) {
|
|
499
|
+
this._ended = true;
|
|
395
500
|
if (this._resolve) {
|
|
396
501
|
this._resolve(this.buildResult());
|
|
397
502
|
}
|
|
@@ -402,7 +507,8 @@ class LambdaResponseBuffered extends Writable {
|
|
|
402
507
|
//
|
|
403
508
|
buildResult() {
|
|
404
509
|
const body = Buffer.concat(this._chunks);
|
|
405
|
-
|
|
510
|
+
// Use direct _headers access to bypass dd-trace interception
|
|
511
|
+
const contentType = this._headers.get("content-type") || "";
|
|
406
512
|
// Determine if response should be base64 encoded
|
|
407
513
|
const isBase64Encoded = this.isBinaryContentType(contentType);
|
|
408
514
|
// Build headers object
|
|
@@ -464,6 +570,8 @@ class LambdaResponseStreaming extends Writable {
|
|
|
464
570
|
this.socket = {
|
|
465
571
|
remoteAddress: "127.0.0.1",
|
|
466
572
|
};
|
|
573
|
+
// Internal state exposed for direct manipulation by safe response methods
|
|
574
|
+
// that need to bypass dd-trace interception
|
|
467
575
|
this._headers = new Map();
|
|
468
576
|
this._headersSent = false;
|
|
469
577
|
this._pendingWrites = [];
|
|
@@ -474,6 +582,65 @@ class LambdaResponseStreaming extends Writable {
|
|
|
474
582
|
if (kOutHeaders) {
|
|
475
583
|
this[kOutHeaders] = Object.create(null);
|
|
476
584
|
}
|
|
585
|
+
// CRITICAL: Define key methods as instance properties to survive Express's
|
|
586
|
+
// setPrototypeOf(res, app.response) in middleware/init.js which would
|
|
587
|
+
// otherwise replace our prototype with ServerResponse.prototype.
|
|
588
|
+
// Instance properties take precedence over prototype properties.
|
|
589
|
+
this.getHeader = this.getHeader.bind(this);
|
|
590
|
+
this.setHeader = this.setHeader.bind(this);
|
|
591
|
+
this.removeHeader = this.removeHeader.bind(this);
|
|
592
|
+
this.hasHeader = this.hasHeader.bind(this);
|
|
593
|
+
this.getHeaders = this.getHeaders.bind(this);
|
|
594
|
+
this.getHeaderNames = this.getHeaderNames.bind(this);
|
|
595
|
+
this.writeHead = this.writeHead.bind(this);
|
|
596
|
+
this.flushHeaders = this.flushHeaders.bind(this);
|
|
597
|
+
this.get = this.get.bind(this);
|
|
598
|
+
this.set = this.set.bind(this);
|
|
599
|
+
this.status = this.status.bind(this);
|
|
600
|
+
this.json = this.json.bind(this);
|
|
601
|
+
this.send = this.send.bind(this);
|
|
602
|
+
this.vary = this.vary.bind(this);
|
|
603
|
+
this.end = this.end.bind(this);
|
|
604
|
+
this.write = this.write.bind(this);
|
|
605
|
+
// Also bind internal Writable methods that are called via prototype chain
|
|
606
|
+
this._write = this._write.bind(this);
|
|
607
|
+
this._final = this._final.bind(this);
|
|
608
|
+
}
|
|
609
|
+
//
|
|
610
|
+
// Internal bypass methods - completely avoid prototype chain lookup
|
|
611
|
+
// These directly access _headers Map, safe from dd-trace interception
|
|
612
|
+
//
|
|
613
|
+
_internalGetHeader(name) {
|
|
614
|
+
const value = this._headers.get(name.toLowerCase());
|
|
615
|
+
return value ? String(value) : undefined;
|
|
616
|
+
}
|
|
617
|
+
_internalSetHeader(name, value) {
|
|
618
|
+
if (!this._headersSent) {
|
|
619
|
+
const lowerName = name.toLowerCase();
|
|
620
|
+
this._headers.set(lowerName, value);
|
|
621
|
+
// Also sync kOutHeaders for any code that expects it
|
|
622
|
+
if (kOutHeaders) {
|
|
623
|
+
const outHeaders = this[kOutHeaders];
|
|
624
|
+
if (outHeaders) {
|
|
625
|
+
outHeaders[lowerName] = [name, value];
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
_internalHasHeader(name) {
|
|
631
|
+
return this._headers.has(name.toLowerCase());
|
|
632
|
+
}
|
|
633
|
+
_internalRemoveHeader(name) {
|
|
634
|
+
if (!this._headersSent) {
|
|
635
|
+
const lowerName = name.toLowerCase();
|
|
636
|
+
this._headers.delete(lowerName);
|
|
637
|
+
if (kOutHeaders) {
|
|
638
|
+
const outHeaders = this[kOutHeaders];
|
|
639
|
+
if (outHeaders) {
|
|
640
|
+
delete outHeaders[lowerName];
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
477
644
|
}
|
|
478
645
|
//
|
|
479
646
|
// Header management
|
|
@@ -528,36 +695,42 @@ class LambdaResponseStreaming extends Writable {
|
|
|
528
695
|
/**
|
|
529
696
|
* Proxy for direct header access (e.g., res.headers['content-type']).
|
|
530
697
|
* Required for compatibility with middleware like helmet that access headers directly.
|
|
698
|
+
* Uses direct _headers access to bypass dd-trace interception.
|
|
531
699
|
*/
|
|
532
700
|
get headers() {
|
|
533
701
|
return new Proxy({}, {
|
|
534
702
|
deleteProperty: (_target, prop) => {
|
|
535
|
-
this.
|
|
703
|
+
if (!this._headersSent) {
|
|
704
|
+
this._headers.delete(String(prop).toLowerCase());
|
|
705
|
+
}
|
|
536
706
|
return true;
|
|
537
707
|
},
|
|
538
708
|
get: (_target, prop) => {
|
|
539
709
|
if (typeof prop === "symbol")
|
|
540
710
|
return undefined;
|
|
541
|
-
return this.
|
|
711
|
+
return this._headers.get(String(prop).toLowerCase());
|
|
542
712
|
},
|
|
543
713
|
getOwnPropertyDescriptor: (_target, prop) => {
|
|
544
|
-
|
|
714
|
+
const lowerProp = String(prop).toLowerCase();
|
|
715
|
+
if (this._headers.has(lowerProp)) {
|
|
545
716
|
return {
|
|
546
717
|
configurable: true,
|
|
547
718
|
enumerable: true,
|
|
548
|
-
value: this.
|
|
719
|
+
value: this._headers.get(lowerProp),
|
|
549
720
|
};
|
|
550
721
|
}
|
|
551
722
|
return undefined;
|
|
552
723
|
},
|
|
553
724
|
has: (_target, prop) => {
|
|
554
|
-
return this.
|
|
725
|
+
return this._headers.has(String(prop).toLowerCase());
|
|
555
726
|
},
|
|
556
727
|
ownKeys: () => {
|
|
557
|
-
return this.
|
|
728
|
+
return Array.from(this._headers.keys());
|
|
558
729
|
},
|
|
559
730
|
set: (_target, prop, value) => {
|
|
560
|
-
this.
|
|
731
|
+
if (!this._headersSent) {
|
|
732
|
+
this._headers.set(String(prop).toLowerCase(), value);
|
|
733
|
+
}
|
|
561
734
|
return true;
|
|
562
735
|
},
|
|
563
736
|
});
|
|
@@ -577,9 +750,10 @@ class LambdaResponseStreaming extends Writable {
|
|
|
577
750
|
headersToSet = statusMessageOrHeaders;
|
|
578
751
|
}
|
|
579
752
|
if (headersToSet) {
|
|
753
|
+
// Use direct _headers access to bypass dd-trace interception
|
|
580
754
|
for (const [key, value] of Object.entries(headersToSet)) {
|
|
581
755
|
if (value !== undefined) {
|
|
582
|
-
this.
|
|
756
|
+
this._headers.set(key.toLowerCase(), String(value));
|
|
583
757
|
}
|
|
584
758
|
}
|
|
585
759
|
}
|
|
@@ -637,7 +811,8 @@ class LambdaResponseStreaming extends Writable {
|
|
|
637
811
|
return this;
|
|
638
812
|
}
|
|
639
813
|
json(data) {
|
|
640
|
-
|
|
814
|
+
// Use direct _headers access to bypass dd-trace interception
|
|
815
|
+
this._headers.set("content-type", "application/json");
|
|
641
816
|
this.end(JSON.stringify(data));
|
|
642
817
|
return this;
|
|
643
818
|
}
|
|
@@ -651,11 +826,12 @@ class LambdaResponseStreaming extends Writable {
|
|
|
651
826
|
/**
|
|
652
827
|
* Add a field to the Vary response header.
|
|
653
828
|
* Used by CORS middleware to indicate response varies by Origin.
|
|
829
|
+
* Uses direct _headers access to bypass dd-trace interception.
|
|
654
830
|
*/
|
|
655
831
|
vary(field) {
|
|
656
|
-
const existing = this.
|
|
832
|
+
const existing = this._headers.get("vary");
|
|
657
833
|
if (!existing) {
|
|
658
|
-
this.
|
|
834
|
+
this._headers.set("vary", field);
|
|
659
835
|
}
|
|
660
836
|
else {
|
|
661
837
|
// Append to existing Vary header if field not already present
|
|
@@ -663,7 +839,7 @@ class LambdaResponseStreaming extends Writable {
|
|
|
663
839
|
.split(",")
|
|
664
840
|
.map((f) => f.trim().toLowerCase());
|
|
665
841
|
if (!fields.includes(field.toLowerCase())) {
|
|
666
|
-
this.
|
|
842
|
+
this._headers.set("vary", `${existing}, ${field}`);
|
|
667
843
|
}
|
|
668
844
|
}
|
|
669
845
|
return this;
|
|
@@ -761,6 +937,7 @@ function runExpressApp(app, req, res) {
|
|
|
761
937
|
*/
|
|
762
938
|
function createLambdaHandler(app, _options) {
|
|
763
939
|
return async (event, context) => {
|
|
940
|
+
let result;
|
|
764
941
|
try {
|
|
765
942
|
// Set current invoke for getCurrentInvokeUuid
|
|
766
943
|
setCurrentInvoke(event, context);
|
|
@@ -770,8 +947,38 @@ function createLambdaHandler(app, _options) {
|
|
|
770
947
|
const res = new LambdaResponseBuffered();
|
|
771
948
|
// Run Express app
|
|
772
949
|
await runExpressApp(app, req, res);
|
|
773
|
-
//
|
|
774
|
-
|
|
950
|
+
// Get Lambda response - await explicitly to ensure we have the result
|
|
951
|
+
result = await res.getResult();
|
|
952
|
+
// Debug: Log the response before returning
|
|
953
|
+
console.log("[createLambdaHandler] Returning response:", JSON.stringify({
|
|
954
|
+
statusCode: result.statusCode,
|
|
955
|
+
headers: result.headers,
|
|
956
|
+
bodyLength: result.body?.length,
|
|
957
|
+
isBase64Encoded: result.isBase64Encoded,
|
|
958
|
+
}));
|
|
959
|
+
return result;
|
|
960
|
+
}
|
|
961
|
+
catch (error) {
|
|
962
|
+
// Log any unhandled errors
|
|
963
|
+
console.error("[createLambdaHandler] Unhandled error:", error);
|
|
964
|
+
if (error instanceof Error) {
|
|
965
|
+
console.error("[createLambdaHandler] Stack:", error.stack);
|
|
966
|
+
}
|
|
967
|
+
// Return a proper error response instead of throwing
|
|
968
|
+
return {
|
|
969
|
+
statusCode: 500,
|
|
970
|
+
headers: { "content-type": "application/json" },
|
|
971
|
+
body: JSON.stringify({
|
|
972
|
+
errors: [
|
|
973
|
+
{
|
|
974
|
+
status: 500,
|
|
975
|
+
title: "Internal Server Error",
|
|
976
|
+
detail: error instanceof Error ? error.message : "Unknown error occurred",
|
|
977
|
+
},
|
|
978
|
+
],
|
|
979
|
+
}),
|
|
980
|
+
isBase64Encoded: false,
|
|
981
|
+
};
|
|
775
982
|
}
|
|
776
983
|
finally {
|
|
777
984
|
// Clear current invoke context
|
|
@@ -909,7 +1116,7 @@ const corsHelper = (config = {}) => {
|
|
|
909
1116
|
};
|
|
910
1117
|
return expressCors(options);
|
|
911
1118
|
};
|
|
912
|
-
var
|
|
1119
|
+
var cors_helper = (config) => {
|
|
913
1120
|
const cors = corsHelper(config);
|
|
914
1121
|
return (req, res, next) => {
|
|
915
1122
|
cors(req, res, (error) => {
|
|
@@ -924,154 +1131,10 @@ var cors = (config) => {
|
|
|
924
1131
|
};
|
|
925
1132
|
};
|
|
926
1133
|
|
|
927
|
-
//
|
|
928
|
-
//
|
|
929
|
-
// Constants
|
|
930
|
-
//
|
|
931
|
-
const DEFAULT_PORT = 8080;
|
|
932
|
-
//
|
|
933
|
-
//
|
|
934
|
-
// Main
|
|
935
|
-
//
|
|
936
|
-
/**
|
|
937
|
-
* Creates and starts an Express server with standard Jaypie middleware.
|
|
938
|
-
*
|
|
939
|
-
* Features:
|
|
940
|
-
* - CORS handling (configurable)
|
|
941
|
-
* - JSON body parsing
|
|
942
|
-
* - Listens on PORT env var (default 8080)
|
|
943
|
-
*
|
|
944
|
-
* Usage:
|
|
945
|
-
* ```ts
|
|
946
|
-
* import express from "express";
|
|
947
|
-
* import { createServer, expressHandler } from "@jaypie/express";
|
|
948
|
-
*
|
|
949
|
-
* const app = express();
|
|
950
|
-
*
|
|
951
|
-
* app.get("/", expressHandler(async (req, res) => {
|
|
952
|
-
* return { message: "Hello World" };
|
|
953
|
-
* }));
|
|
954
|
-
*
|
|
955
|
-
* const { server, port } = await createServer(app);
|
|
956
|
-
* console.log(`Server running on port ${port}`);
|
|
957
|
-
* ```
|
|
958
|
-
*
|
|
959
|
-
* @param app - Express application instance
|
|
960
|
-
* @param options - Server configuration options
|
|
961
|
-
* @returns Promise resolving to server instance and port
|
|
962
|
-
*/
|
|
963
|
-
async function createServer(app, options = {}) {
|
|
964
|
-
const { cors: corsConfig, jsonLimit = "1mb", middleware = [], port: portOption, } = options;
|
|
965
|
-
// Determine port
|
|
966
|
-
const port = typeof portOption === "string"
|
|
967
|
-
? parseInt(portOption, 10)
|
|
968
|
-
: (portOption ?? parseInt(process.env.PORT || String(DEFAULT_PORT), 10));
|
|
969
|
-
// Apply CORS middleware (unless explicitly disabled)
|
|
970
|
-
if (corsConfig !== false) {
|
|
971
|
-
app.use(cors(corsConfig));
|
|
972
|
-
}
|
|
973
|
-
// Apply JSON body parser
|
|
974
|
-
// Note: We use dynamic import to avoid requiring express as a direct dependency
|
|
975
|
-
const express = await import('express');
|
|
976
|
-
app.use(express.json({ limit: jsonLimit }));
|
|
977
|
-
// Apply additional middleware
|
|
978
|
-
for (const mw of middleware) {
|
|
979
|
-
app.use(mw);
|
|
980
|
-
}
|
|
981
|
-
// Start server
|
|
982
|
-
return new Promise((resolve, reject) => {
|
|
983
|
-
try {
|
|
984
|
-
const server = app.listen(port, () => {
|
|
985
|
-
// Get the actual port (important when port 0 is passed to get an ephemeral port)
|
|
986
|
-
const address = server.address();
|
|
987
|
-
const actualPort = address?.port ?? port;
|
|
988
|
-
log.info(`Server listening on port ${actualPort}`);
|
|
989
|
-
resolve({ port: actualPort, server });
|
|
990
|
-
});
|
|
991
|
-
server.on("error", (error) => {
|
|
992
|
-
log.error("Server error", { error });
|
|
993
|
-
reject(error);
|
|
994
|
-
});
|
|
995
|
-
}
|
|
996
|
-
catch (error) {
|
|
997
|
-
reject(error);
|
|
998
|
-
}
|
|
999
|
-
});
|
|
1000
|
-
}
|
|
1001
|
-
|
|
1002
|
-
//
|
|
1003
|
-
//
|
|
1004
|
-
// Constants
|
|
1005
|
-
//
|
|
1006
|
-
const HEADER_AMZN_REQUEST_ID$1 = "x-amzn-request-id";
|
|
1007
|
-
const ENV_AMZN_TRACE_ID = "_X_AMZN_TRACE_ID";
|
|
1008
1134
|
//
|
|
1009
1135
|
//
|
|
1010
1136
|
// Helper Functions
|
|
1011
1137
|
//
|
|
1012
|
-
/**
|
|
1013
|
-
* Extract request ID from X-Ray trace ID environment variable
|
|
1014
|
-
* Format: Root=1-5e6b4a90-example;Parent=example;Sampled=1
|
|
1015
|
-
* We extract the trace ID from the Root segment
|
|
1016
|
-
*/
|
|
1017
|
-
function parseTraceId(traceId) {
|
|
1018
|
-
if (!traceId)
|
|
1019
|
-
return undefined;
|
|
1020
|
-
// Extract the Root segment (format: Root=1-{timestamp}-{uuid})
|
|
1021
|
-
const rootMatch = traceId.match(/Root=([^;]+)/);
|
|
1022
|
-
if (rootMatch && rootMatch[1]) {
|
|
1023
|
-
return rootMatch[1];
|
|
1024
|
-
}
|
|
1025
|
-
return undefined;
|
|
1026
|
-
}
|
|
1027
|
-
//
|
|
1028
|
-
//
|
|
1029
|
-
// Main
|
|
1030
|
-
//
|
|
1031
|
-
/**
|
|
1032
|
-
* Get the current invoke UUID from Lambda Web Adapter context.
|
|
1033
|
-
* This function extracts the request ID from either:
|
|
1034
|
-
* 1. The x-amzn-request-id header (set by Lambda Web Adapter)
|
|
1035
|
-
* 2. The _X_AMZN_TRACE_ID environment variable (set by Lambda runtime)
|
|
1036
|
-
*
|
|
1037
|
-
* @param req - Optional Express request object to extract headers from
|
|
1038
|
-
* @returns The AWS request ID or undefined if not in Lambda context
|
|
1039
|
-
*/
|
|
1040
|
-
function getWebAdapterUuid(req) {
|
|
1041
|
-
// First, try to get from request headers
|
|
1042
|
-
if (req && req.headers) {
|
|
1043
|
-
const headerValue = req.headers[HEADER_AMZN_REQUEST_ID$1];
|
|
1044
|
-
if (headerValue) {
|
|
1045
|
-
return Array.isArray(headerValue) ? headerValue[0] : headerValue;
|
|
1046
|
-
}
|
|
1047
|
-
}
|
|
1048
|
-
// Fall back to environment variable (X-Ray trace ID)
|
|
1049
|
-
const traceId = process.env[ENV_AMZN_TRACE_ID];
|
|
1050
|
-
if (traceId) {
|
|
1051
|
-
return parseTraceId(traceId);
|
|
1052
|
-
}
|
|
1053
|
-
return undefined;
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
//
|
|
1057
|
-
//
|
|
1058
|
-
// Constants
|
|
1059
|
-
//
|
|
1060
|
-
const HEADER_AMZN_REQUEST_ID = "x-amzn-request-id";
|
|
1061
|
-
//
|
|
1062
|
-
//
|
|
1063
|
-
// Helper Functions
|
|
1064
|
-
//
|
|
1065
|
-
/**
|
|
1066
|
-
* Detect if we're running in Lambda Web Adapter mode.
|
|
1067
|
-
* Web Adapter sets the x-amzn-request-id header on requests.
|
|
1068
|
-
*/
|
|
1069
|
-
function isWebAdapterMode(req) {
|
|
1070
|
-
if (req && req.headers && req.headers[HEADER_AMZN_REQUEST_ID]) {
|
|
1071
|
-
return true;
|
|
1072
|
-
}
|
|
1073
|
-
return false;
|
|
1074
|
-
}
|
|
1075
1138
|
/**
|
|
1076
1139
|
* Get UUID from Jaypie Lambda adapter context.
|
|
1077
1140
|
* This is set by createLambdaHandler/createLambdaStreamHandler.
|
|
@@ -1088,8 +1151,12 @@ function getJaypieAdapterUuid() {
|
|
|
1088
1151
|
* The Jaypie adapter attaches _lambdaContext to the request.
|
|
1089
1152
|
*/
|
|
1090
1153
|
function getRequestContextUuid(req) {
|
|
1091
|
-
if (req && req._lambdaContext
|
|
1092
|
-
|
|
1154
|
+
if (req && req._lambdaContext) {
|
|
1155
|
+
const lambdaContext = req
|
|
1156
|
+
._lambdaContext;
|
|
1157
|
+
if (lambdaContext.awsRequestId) {
|
|
1158
|
+
return lambdaContext.awsRequestId;
|
|
1159
|
+
}
|
|
1093
1160
|
}
|
|
1094
1161
|
return undefined;
|
|
1095
1162
|
}
|
|
@@ -1099,29 +1166,20 @@ function getRequestContextUuid(req) {
|
|
|
1099
1166
|
//
|
|
1100
1167
|
/**
|
|
1101
1168
|
* Get the current invoke UUID from Lambda context.
|
|
1102
|
-
* Works with Jaypie Lambda adapter
|
|
1169
|
+
* Works with Jaypie Lambda adapter (createLambdaHandler/createLambdaStreamHandler).
|
|
1103
1170
|
*
|
|
1104
1171
|
* @param req - Optional Express request object. Used to extract context
|
|
1105
|
-
* from
|
|
1172
|
+
* from Jaypie adapter's _lambdaContext.
|
|
1106
1173
|
* @returns The AWS request ID or undefined if not in Lambda context
|
|
1107
1174
|
*/
|
|
1108
1175
|
function getCurrentInvokeUuid(req) {
|
|
1109
|
-
// Priority 1:
|
|
1110
|
-
if (isWebAdapterMode(req)) {
|
|
1111
|
-
return getWebAdapterUuid(req);
|
|
1112
|
-
}
|
|
1113
|
-
// Priority 2: Request has Lambda context attached (Jaypie adapter)
|
|
1176
|
+
// Priority 1: Request has Lambda context attached (Jaypie adapter)
|
|
1114
1177
|
const requestContextUuid = getRequestContextUuid(req);
|
|
1115
1178
|
if (requestContextUuid) {
|
|
1116
1179
|
return requestContextUuid;
|
|
1117
1180
|
}
|
|
1118
|
-
// Priority
|
|
1119
|
-
|
|
1120
|
-
if (jaypieAdapterUuid) {
|
|
1121
|
-
return jaypieAdapterUuid;
|
|
1122
|
-
}
|
|
1123
|
-
// Fallback: Web Adapter env var
|
|
1124
|
-
return getWebAdapterUuid();
|
|
1181
|
+
// Priority 2: Global context from Jaypie adapter
|
|
1182
|
+
return getJaypieAdapterUuid();
|
|
1125
1183
|
}
|
|
1126
1184
|
|
|
1127
1185
|
//
|
|
@@ -1135,7 +1193,11 @@ function getCurrentInvokeUuid(req) {
|
|
|
1135
1193
|
*/
|
|
1136
1194
|
function safeGetHeader(res, name) {
|
|
1137
1195
|
try {
|
|
1138
|
-
// Try
|
|
1196
|
+
// Try internal method first (completely bypasses dd-trace)
|
|
1197
|
+
if (typeof res._internalGetHeader === "function") {
|
|
1198
|
+
return res._internalGetHeader(name);
|
|
1199
|
+
}
|
|
1200
|
+
// Fall back to _headers Map access (Lambda adapter, avoids dd-trace)
|
|
1139
1201
|
if (res._headers instanceof Map) {
|
|
1140
1202
|
const value = res._headers.get(name.toLowerCase());
|
|
1141
1203
|
return value ? String(value) : undefined;
|
|
@@ -1163,7 +1225,12 @@ function safeGetHeader(res, name) {
|
|
|
1163
1225
|
*/
|
|
1164
1226
|
function safeSetHeader(res, name, value) {
|
|
1165
1227
|
try {
|
|
1166
|
-
// Try
|
|
1228
|
+
// Try internal method first (completely bypasses dd-trace)
|
|
1229
|
+
if (typeof res._internalSetHeader === "function") {
|
|
1230
|
+
res._internalSetHeader(name, value);
|
|
1231
|
+
return;
|
|
1232
|
+
}
|
|
1233
|
+
// Fall back to _headers Map access (Lambda adapter, avoids dd-trace)
|
|
1167
1234
|
if (res._headers instanceof Map) {
|
|
1168
1235
|
res._headers.set(name.toLowerCase(), value);
|
|
1169
1236
|
return;
|
|
@@ -1293,21 +1360,41 @@ const logger$1 = log;
|
|
|
1293
1360
|
// Helpers - Safe response methods to bypass dd-trace interception
|
|
1294
1361
|
//
|
|
1295
1362
|
/**
|
|
1296
|
-
* Check if response is a Lambda mock response with direct
|
|
1363
|
+
* Check if response is a Lambda mock response with direct internal access.
|
|
1364
|
+
* Uses Symbol marker to survive prototype chain modifications from Express and dd-trace.
|
|
1297
1365
|
*/
|
|
1298
1366
|
function isLambdaMockResponse(res) {
|
|
1299
|
-
return res
|
|
1367
|
+
return res[JAYPIE_LAMBDA_MOCK] === true;
|
|
1300
1368
|
}
|
|
1301
1369
|
/**
|
|
1302
1370
|
* Safely send a JSON response, avoiding dd-trace interception.
|
|
1303
|
-
* For Lambda mock responses, directly
|
|
1371
|
+
* For Lambda mock responses, directly manipulates internal state instead of
|
|
1372
|
+
* using stream methods (write/end) which dd-trace intercepts.
|
|
1304
1373
|
*/
|
|
1305
1374
|
function safeSendJson(res, statusCode, data) {
|
|
1306
1375
|
if (isLambdaMockResponse(res)) {
|
|
1307
|
-
//
|
|
1308
|
-
res.
|
|
1376
|
+
// Use internal method to set header (completely bypasses dd-trace)
|
|
1377
|
+
if (typeof res._internalSetHeader === "function") {
|
|
1378
|
+
res._internalSetHeader("content-type", "application/json");
|
|
1379
|
+
}
|
|
1380
|
+
else {
|
|
1381
|
+
// Fall back to direct _headers manipulation
|
|
1382
|
+
res._headers.set("content-type", "application/json");
|
|
1383
|
+
}
|
|
1309
1384
|
res.statusCode = statusCode;
|
|
1310
|
-
|
|
1385
|
+
// Directly push to chunks array instead of using stream write/end
|
|
1386
|
+
const chunk = Buffer.from(JSON.stringify(data));
|
|
1387
|
+
res._chunks.push(chunk);
|
|
1388
|
+
res._headersSent = true;
|
|
1389
|
+
// Mark as ended so getResult() resolves immediately
|
|
1390
|
+
res._ended = true;
|
|
1391
|
+
// Signal completion if a promise is waiting
|
|
1392
|
+
if (res._resolve) {
|
|
1393
|
+
res._resolve(res.buildResult());
|
|
1394
|
+
}
|
|
1395
|
+
// Emit "finish" event so runExpressApp's promise resolves
|
|
1396
|
+
console.log("[safeSendJson] Emitting finish event");
|
|
1397
|
+
res.emit("finish");
|
|
1311
1398
|
return;
|
|
1312
1399
|
}
|
|
1313
1400
|
// Fall back to standard Express methods for real responses
|
|
@@ -1315,18 +1402,27 @@ function safeSendJson(res, statusCode, data) {
|
|
|
1315
1402
|
}
|
|
1316
1403
|
/**
|
|
1317
1404
|
* Safely send a response body, avoiding dd-trace interception.
|
|
1318
|
-
* For Lambda mock responses, directly
|
|
1405
|
+
* For Lambda mock responses, directly manipulates internal state instead of
|
|
1406
|
+
* using stream methods (write/end) which dd-trace intercepts.
|
|
1319
1407
|
*/
|
|
1320
1408
|
function safeSend(res, statusCode, body) {
|
|
1321
1409
|
if (isLambdaMockResponse(res)) {
|
|
1322
|
-
// Direct
|
|
1410
|
+
// Direct internal state manipulation - bypasses dd-trace completely
|
|
1323
1411
|
res.statusCode = statusCode;
|
|
1324
1412
|
if (body !== undefined) {
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1413
|
+
const chunk = Buffer.from(body);
|
|
1414
|
+
res._chunks.push(chunk);
|
|
1415
|
+
}
|
|
1416
|
+
res._headersSent = true;
|
|
1417
|
+
// Mark as ended so getResult() resolves immediately
|
|
1418
|
+
res._ended = true;
|
|
1419
|
+
// Signal completion if a promise is waiting
|
|
1420
|
+
if (res._resolve) {
|
|
1421
|
+
res._resolve(res.buildResult());
|
|
1422
|
+
}
|
|
1423
|
+
// Emit "finish" event so runExpressApp's promise resolves
|
|
1424
|
+
console.log("[safeSend] Emitting finish event");
|
|
1425
|
+
res.emit("finish");
|
|
1330
1426
|
return;
|
|
1331
1427
|
}
|
|
1332
1428
|
// Fall back to standard Express methods for real responses
|
|
@@ -1593,7 +1689,18 @@ function expressHandler(handlerOrOptions, optionsOrHandler) {
|
|
|
1593
1689
|
}
|
|
1594
1690
|
}
|
|
1595
1691
|
catch (error) {
|
|
1596
|
-
|
|
1692
|
+
// Use console.error for raw stack trace to ensure it appears in CloudWatch
|
|
1693
|
+
// Handle both Error objects and plain thrown values
|
|
1694
|
+
const errorMessage = error instanceof Error
|
|
1695
|
+
? error.message
|
|
1696
|
+
: typeof error === "object" && error !== null
|
|
1697
|
+
? JSON.stringify(error)
|
|
1698
|
+
: String(error);
|
|
1699
|
+
const errorStack = error instanceof Error
|
|
1700
|
+
? error.stack
|
|
1701
|
+
: new Error("Stack trace").stack?.replace("Error: Stack trace", `Error: ${errorMessage}`);
|
|
1702
|
+
console.error("Express response error stack trace:", errorStack);
|
|
1703
|
+
log.fatal(`Express encountered an error while sending the response: ${errorMessage}`);
|
|
1597
1704
|
log.var({ responseError: error });
|
|
1598
1705
|
}
|
|
1599
1706
|
// Log response
|
|
@@ -1693,14 +1800,13 @@ const logger = log;
|
|
|
1693
1800
|
// Helper
|
|
1694
1801
|
//
|
|
1695
1802
|
/**
|
|
1696
|
-
*
|
|
1803
|
+
* Get error body from an error
|
|
1697
1804
|
*/
|
|
1698
|
-
function
|
|
1805
|
+
function getErrorBody(error) {
|
|
1699
1806
|
const isJaypieError = error.isProjectError;
|
|
1700
|
-
|
|
1807
|
+
return isJaypieError
|
|
1701
1808
|
? (error.body?.() ?? { error: error.message })
|
|
1702
1809
|
: new UnhandledError().body();
|
|
1703
|
-
return `event: error\ndata: ${JSON.stringify(body)}\n\n`;
|
|
1704
1810
|
}
|
|
1705
1811
|
function expressStreamHandler(handlerOrOptions, optionsOrHandler) {
|
|
1706
1812
|
/* eslint-enable no-redeclare */
|
|
@@ -1720,7 +1826,8 @@ function expressStreamHandler(handlerOrOptions, optionsOrHandler) {
|
|
|
1720
1826
|
//
|
|
1721
1827
|
// Validate
|
|
1722
1828
|
//
|
|
1723
|
-
|
|
1829
|
+
const format = options.format ?? "sse";
|
|
1830
|
+
let { chaos, contentType = getContentTypeForFormat(format), locals, name, secrets, setup = [], teardown = [], unavailable, validate, } = options;
|
|
1724
1831
|
if (typeof handler !== "function") {
|
|
1725
1832
|
throw new BadRequestError(`Argument "${handler}" doesn't match type "function"`);
|
|
1726
1833
|
}
|
|
@@ -1858,9 +1965,10 @@ function expressStreamHandler(handlerOrOptions, optionsOrHandler) {
|
|
|
1858
1965
|
log.fatal("Caught unhandled error in stream handler");
|
|
1859
1966
|
log.info.var({ unhandledError: error.message });
|
|
1860
1967
|
}
|
|
1861
|
-
// Write error
|
|
1968
|
+
// Write error in the appropriate format
|
|
1862
1969
|
try {
|
|
1863
|
-
|
|
1970
|
+
const errorBody = getErrorBody(error);
|
|
1971
|
+
res.write(formatStreamError(errorBody, format));
|
|
1864
1972
|
}
|
|
1865
1973
|
catch {
|
|
1866
1974
|
// Response may already be closed
|
|
@@ -1969,5 +2077,5 @@ const noContentRoute = routes.noContentRoute;
|
|
|
1969
2077
|
const notFoundRoute = routes.notFoundRoute;
|
|
1970
2078
|
const notImplementedRoute = routes.notImplementedRoute;
|
|
1971
2079
|
|
|
1972
|
-
export { EXPRESS, LambdaRequest, LambdaResponseBuffered, LambdaResponseStreaming, badRequestRoute, cors, createLambdaHandler, createLambdaStreamHandler,
|
|
2080
|
+
export { EXPRESS, LambdaRequest, LambdaResponseBuffered, LambdaResponseStreaming, badRequestRoute, cors_helper as cors, createLambdaHandler, createLambdaStreamHandler, echoRoute, expressHandler, httpHandler as expressHttpCodeHandler, expressStreamHandler, forbiddenRoute, getCurrentInvoke, getCurrentInvokeUuid, goneRoute, methodNotAllowedRoute, noContentRoute, notFoundRoute, notImplementedRoute };
|
|
1973
2081
|
//# sourceMappingURL=index.js.map
|