@jaypie/express 1.2.32 → 1.2.34
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 +7 -0
- package/dist/cjs/adapter/LambdaResponseStreaming.d.ts +8 -0
- package/dist/cjs/adapter/headers.helper.d.ts +15 -0
- package/dist/cjs/adapter/types.d.ts +1 -0
- package/dist/cjs/index.cjs +98 -34
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +15 -0
- package/dist/esm/adapter/LambdaResponseBuffered.d.ts +7 -0
- package/dist/esm/adapter/LambdaResponseStreaming.d.ts +8 -0
- package/dist/esm/adapter/headers.helper.d.ts +15 -0
- package/dist/esm/adapter/types.d.ts +1 -0
- package/dist/esm/index.d.ts +15 -0
- package/dist/esm/index.js +98 -34
- package/dist/esm/index.js.map +1 -1
- package/package.json +3 -1
|
@@ -36,6 +36,13 @@ export declare class LambdaResponseBuffered extends Writable {
|
|
|
36
36
|
*/
|
|
37
37
|
get headers(): Record<string, string | string[] | undefined>;
|
|
38
38
|
writeHead(statusCode: number, statusMessageOrHeaders?: OutgoingHttpHeaders | string, headers?: OutgoingHttpHeaders): this;
|
|
39
|
+
/**
|
|
40
|
+
* Node's implicit-header hook, called before the first body byte commits.
|
|
41
|
+
* Routes through this.writeHead resolved at call time so wrappers installed
|
|
42
|
+
* mid-request (on-headers, and through it express-session, morgan,
|
|
43
|
+
* compression, express-openid-connect) run their listeners.
|
|
44
|
+
*/
|
|
45
|
+
_implicitHeader(): void;
|
|
39
46
|
get headersSent(): boolean;
|
|
40
47
|
/**
|
|
41
48
|
* Express-style alias for getHeader().
|
|
@@ -36,8 +36,16 @@ export declare class LambdaResponseStreaming extends Writable {
|
|
|
36
36
|
*/
|
|
37
37
|
get headers(): Record<string, string | string[] | undefined>;
|
|
38
38
|
writeHead(statusCode: number, statusMessageOrHeaders?: OutgoingHttpHeaders | string, headers?: OutgoingHttpHeaders): this;
|
|
39
|
+
/**
|
|
40
|
+
* Node's implicit-header hook, called before the first body byte commits.
|
|
41
|
+
* Routes through this.writeHead resolved at call time so wrappers installed
|
|
42
|
+
* mid-request (on-headers, and through it express-session, morgan,
|
|
43
|
+
* compression, express-openid-connect) run their listeners.
|
|
44
|
+
*/
|
|
45
|
+
_implicitHeader(): void;
|
|
39
46
|
get headersSent(): boolean;
|
|
40
47
|
flushHeaders(): void;
|
|
48
|
+
private _commitHeaders;
|
|
41
49
|
/**
|
|
42
50
|
* Express-style alias for getHeader().
|
|
43
51
|
* Used by middleware like decorateResponse that use res.get().
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const SET_COOKIE = "set-cookie";
|
|
2
|
+
/**
|
|
3
|
+
* Normalize a header value for storage, preserving arrays.
|
|
4
|
+
* Node's ServerResponse keeps multi-value headers as arrays; stringifying
|
|
5
|
+
* here would fold them into a single comma-separated value.
|
|
6
|
+
*/
|
|
7
|
+
export declare function normalizeHeaderValue(value: number | string | string[]): string | string[];
|
|
8
|
+
/**
|
|
9
|
+
* Split stored headers into a single-value header record and a cookies
|
|
10
|
+
* array, matching the Lambda Function URL (v2) response shape.
|
|
11
|
+
*/
|
|
12
|
+
export declare function splitCookieHeaders(source: Map<string, string | string[]>): {
|
|
13
|
+
cookies: string[];
|
|
14
|
+
headers: Record<string, string>;
|
|
15
|
+
};
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -278,6 +278,50 @@ function createLambdaRequest(event, context) {
|
|
|
278
278
|
});
|
|
279
279
|
}
|
|
280
280
|
|
|
281
|
+
//
|
|
282
|
+
//
|
|
283
|
+
// Constants
|
|
284
|
+
//
|
|
285
|
+
// Set-Cookie is the one header that must never be comma-folded: cookie
|
|
286
|
+
// expiry dates contain commas, so a folded value is unparseable. Lambda
|
|
287
|
+
// carries these out-of-band in the `cookies` field of the v2 response
|
|
288
|
+
// payload and of the response-streaming metadata prelude.
|
|
289
|
+
const SET_COOKIE = "set-cookie";
|
|
290
|
+
//
|
|
291
|
+
//
|
|
292
|
+
// Functions
|
|
293
|
+
//
|
|
294
|
+
/**
|
|
295
|
+
* Normalize a header value for storage, preserving arrays.
|
|
296
|
+
* Node's ServerResponse keeps multi-value headers as arrays; stringifying
|
|
297
|
+
* here would fold them into a single comma-separated value.
|
|
298
|
+
*/
|
|
299
|
+
function normalizeHeaderValue(value) {
|
|
300
|
+
return Array.isArray(value) ? value.map(String) : String(value);
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Split stored headers into a single-value header record and a cookies
|
|
304
|
+
* array, matching the Lambda Function URL (v2) response shape.
|
|
305
|
+
*/
|
|
306
|
+
function splitCookieHeaders(source) {
|
|
307
|
+
const cookies = [];
|
|
308
|
+
const headers = {};
|
|
309
|
+
for (const [key, value] of source) {
|
|
310
|
+
if (key === SET_COOKIE) {
|
|
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
|
+
return { cookies, headers };
|
|
323
|
+
}
|
|
324
|
+
|
|
281
325
|
//
|
|
282
326
|
//
|
|
283
327
|
// Constants
|
|
@@ -340,6 +384,7 @@ class LambdaResponseBuffered extends node_stream.Writable {
|
|
|
340
384
|
this.getHeaders = this.getHeaders.bind(this);
|
|
341
385
|
this.getHeaderNames = this.getHeaderNames.bind(this);
|
|
342
386
|
this.writeHead = this.writeHead.bind(this);
|
|
387
|
+
this._implicitHeader = this._implicitHeader.bind(this);
|
|
343
388
|
this.get = this.get.bind(this);
|
|
344
389
|
this.set = this.set.bind(this);
|
|
345
390
|
this.status = this.status.bind(this);
|
|
@@ -415,13 +460,14 @@ class LambdaResponseBuffered extends node_stream.Writable {
|
|
|
415
460
|
return this;
|
|
416
461
|
}
|
|
417
462
|
const lowerName = name.toLowerCase();
|
|
418
|
-
|
|
463
|
+
const normalized = normalizeHeaderValue(value);
|
|
464
|
+
this._headers.set(lowerName, normalized);
|
|
419
465
|
// Sync with kOutHeaders for dd-trace compatibility
|
|
420
466
|
// Node stores as { 'header-name': ['Header-Name', value] }
|
|
421
467
|
if (kOutHeaders$1) {
|
|
422
468
|
const outHeaders = this[kOutHeaders$1];
|
|
423
469
|
if (outHeaders) {
|
|
424
|
-
outHeaders[lowerName] = [name,
|
|
470
|
+
outHeaders[lowerName] = [name, normalized];
|
|
425
471
|
}
|
|
426
472
|
}
|
|
427
473
|
return this;
|
|
@@ -495,6 +541,9 @@ class LambdaResponseBuffered extends node_stream.Writable {
|
|
|
495
541
|
});
|
|
496
542
|
}
|
|
497
543
|
writeHead(statusCode, statusMessageOrHeaders, headers) {
|
|
544
|
+
if (this._headersSent) {
|
|
545
|
+
return this;
|
|
546
|
+
}
|
|
498
547
|
this.statusCode = statusCode;
|
|
499
548
|
let headersToSet;
|
|
500
549
|
if (typeof statusMessageOrHeaders === "string") {
|
|
@@ -509,13 +558,24 @@ class LambdaResponseBuffered extends node_stream.Writable {
|
|
|
509
558
|
// Use direct _headers access to bypass dd-trace interception
|
|
510
559
|
for (const [key, value] of Object.entries(headersToSet)) {
|
|
511
560
|
if (value !== undefined) {
|
|
512
|
-
this._headers.set(key.toLowerCase(),
|
|
561
|
+
this._headers.set(key.toLowerCase(), normalizeHeaderValue(value));
|
|
513
562
|
}
|
|
514
563
|
}
|
|
515
564
|
}
|
|
516
565
|
this._headersSent = true;
|
|
517
566
|
return this;
|
|
518
567
|
}
|
|
568
|
+
/**
|
|
569
|
+
* Node's implicit-header hook, called before the first body byte commits.
|
|
570
|
+
* Routes through this.writeHead resolved at call time so wrappers installed
|
|
571
|
+
* mid-request (on-headers, and through it express-session, morgan,
|
|
572
|
+
* compression, express-openid-connect) run their listeners.
|
|
573
|
+
*/
|
|
574
|
+
_implicitHeader() {
|
|
575
|
+
if (!this._headersSent) {
|
|
576
|
+
this.writeHead(this.statusCode);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
519
579
|
get headersSent() {
|
|
520
580
|
return this._headersSent;
|
|
521
581
|
}
|
|
@@ -537,7 +597,7 @@ class LambdaResponseBuffered extends node_stream.Writable {
|
|
|
537
597
|
*/
|
|
538
598
|
set(name, value) {
|
|
539
599
|
if (!this._headersSent) {
|
|
540
|
-
this._headers.set(name.toLowerCase(),
|
|
600
|
+
this._headers.set(name.toLowerCase(), normalizeHeaderValue(value));
|
|
541
601
|
}
|
|
542
602
|
return this;
|
|
543
603
|
}
|
|
@@ -587,11 +647,13 @@ class LambdaResponseBuffered extends node_stream.Writable {
|
|
|
587
647
|
const buffer = Buffer.isBuffer(chunk)
|
|
588
648
|
? chunk
|
|
589
649
|
: Buffer.from(chunk, encoding);
|
|
650
|
+
this._implicitHeader();
|
|
590
651
|
this._chunks.push(buffer);
|
|
591
652
|
this._headersSent = true;
|
|
592
653
|
callback();
|
|
593
654
|
}
|
|
594
655
|
_final(callback) {
|
|
656
|
+
this._implicitHeader();
|
|
595
657
|
this._ended = true;
|
|
596
658
|
if (this._resolve) {
|
|
597
659
|
this._resolve(this.buildResult());
|
|
@@ -607,23 +669,8 @@ class LambdaResponseBuffered extends node_stream.Writable {
|
|
|
607
669
|
const contentType = this._headers.get("content-type") || "";
|
|
608
670
|
// Determine if response should be base64 encoded
|
|
609
671
|
const isBase64Encoded = this.isBinaryContentType(contentType);
|
|
610
|
-
// Build headers object
|
|
611
|
-
const headers =
|
|
612
|
-
const cookies = [];
|
|
613
|
-
for (const [key, value] of this._headers) {
|
|
614
|
-
if (key === "set-cookie") {
|
|
615
|
-
// Collect Set-Cookie headers for v2 response format
|
|
616
|
-
if (Array.isArray(value)) {
|
|
617
|
-
cookies.push(...value);
|
|
618
|
-
}
|
|
619
|
-
else {
|
|
620
|
-
cookies.push(value);
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
else {
|
|
624
|
-
headers[key] = Array.isArray(value) ? value.join(", ") : String(value);
|
|
625
|
-
}
|
|
626
|
-
}
|
|
672
|
+
// Build headers object, carrying Set-Cookie out-of-band (v2 format)
|
|
673
|
+
const { cookies, headers } = splitCookieHeaders(this._headers);
|
|
627
674
|
const result = {
|
|
628
675
|
body: isBase64Encoded ? body.toString("base64") : body.toString("utf8"),
|
|
629
676
|
headers,
|
|
@@ -698,6 +745,8 @@ class LambdaResponseStreaming extends node_stream.Writable {
|
|
|
698
745
|
this.getHeaderNames = this.getHeaderNames.bind(this);
|
|
699
746
|
this.writeHead = this.writeHead.bind(this);
|
|
700
747
|
this.flushHeaders = this.flushHeaders.bind(this);
|
|
748
|
+
this._implicitHeader = this._implicitHeader.bind(this);
|
|
749
|
+
this._commitHeaders = this._commitHeaders.bind(this);
|
|
701
750
|
this.get = this.get.bind(this);
|
|
702
751
|
this.set = this.set.bind(this);
|
|
703
752
|
this.status = this.status.bind(this);
|
|
@@ -756,13 +805,14 @@ class LambdaResponseStreaming extends node_stream.Writable {
|
|
|
756
805
|
return this;
|
|
757
806
|
}
|
|
758
807
|
const lowerName = name.toLowerCase();
|
|
759
|
-
|
|
808
|
+
const normalized = normalizeHeaderValue(value);
|
|
809
|
+
this._headers.set(lowerName, normalized);
|
|
760
810
|
// Sync with kOutHeaders for dd-trace compatibility
|
|
761
811
|
// Node stores as { 'header-name': ['Header-Name', value] }
|
|
762
812
|
if (kOutHeaders) {
|
|
763
813
|
const outHeaders = this[kOutHeaders];
|
|
764
814
|
if (outHeaders) {
|
|
765
|
-
outHeaders[lowerName] = [name,
|
|
815
|
+
outHeaders[lowerName] = [name, normalized];
|
|
766
816
|
}
|
|
767
817
|
}
|
|
768
818
|
return this;
|
|
@@ -857,24 +907,36 @@ class LambdaResponseStreaming extends node_stream.Writable {
|
|
|
857
907
|
// Use direct _headers access to bypass dd-trace interception
|
|
858
908
|
for (const [key, value] of Object.entries(headersToSet)) {
|
|
859
909
|
if (value !== undefined) {
|
|
860
|
-
this._headers.set(key.toLowerCase(),
|
|
910
|
+
this._headers.set(key.toLowerCase(), normalizeHeaderValue(value));
|
|
861
911
|
}
|
|
862
912
|
}
|
|
863
913
|
}
|
|
864
|
-
this.
|
|
914
|
+
this._commitHeaders();
|
|
865
915
|
return this;
|
|
866
916
|
}
|
|
917
|
+
/**
|
|
918
|
+
* Node's implicit-header hook, called before the first body byte commits.
|
|
919
|
+
* Routes through this.writeHead resolved at call time so wrappers installed
|
|
920
|
+
* mid-request (on-headers, and through it express-session, morgan,
|
|
921
|
+
* compression, express-openid-connect) run their listeners.
|
|
922
|
+
*/
|
|
923
|
+
_implicitHeader() {
|
|
924
|
+
if (!this._headersSent) {
|
|
925
|
+
this.writeHead(this.statusCode);
|
|
926
|
+
}
|
|
927
|
+
}
|
|
867
928
|
get headersSent() {
|
|
868
929
|
return this._headersSent;
|
|
869
930
|
}
|
|
870
931
|
flushHeaders() {
|
|
932
|
+
this._implicitHeader();
|
|
933
|
+
}
|
|
934
|
+
_commitHeaders() {
|
|
871
935
|
if (this._headersSent) {
|
|
872
936
|
return;
|
|
873
937
|
}
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
headers[key] = Array.isArray(value) ? value.join(", ") : String(value);
|
|
877
|
-
}
|
|
938
|
+
// Set-Cookie travels in metadata.cookies, never folded into headers
|
|
939
|
+
const { cookies, headers } = splitCookieHeaders(this._headers);
|
|
878
940
|
// Lambda streaming requires body content for metadata to be transmitted.
|
|
879
941
|
// Convert 204 No Content to 200 OK with empty JSON body as workaround.
|
|
880
942
|
// See: https://github.com/finlaysonstudio/jaypie/issues/178
|
|
@@ -889,6 +951,10 @@ class LambdaResponseStreaming extends node_stream.Writable {
|
|
|
889
951
|
headers,
|
|
890
952
|
statusCode,
|
|
891
953
|
};
|
|
954
|
+
// Only include cookies if present (v2 format)
|
|
955
|
+
if (cookies.length > 0) {
|
|
956
|
+
metadata.cookies = cookies;
|
|
957
|
+
}
|
|
892
958
|
// Create wrapped stream with metadata
|
|
893
959
|
this._wrappedStream = awslambda.HttpResponseStream.from(this._responseStream, metadata);
|
|
894
960
|
this._headersSent = true;
|
|
@@ -917,7 +983,7 @@ class LambdaResponseStreaming extends node_stream.Writable {
|
|
|
917
983
|
*/
|
|
918
984
|
set(name, value) {
|
|
919
985
|
if (!this._headersSent) {
|
|
920
|
-
this._headers.set(name.toLowerCase(),
|
|
986
|
+
this._headers.set(name.toLowerCase(), normalizeHeaderValue(value));
|
|
921
987
|
}
|
|
922
988
|
return this;
|
|
923
989
|
}
|
|
@@ -971,7 +1037,7 @@ class LambdaResponseStreaming extends node_stream.Writable {
|
|
|
971
1037
|
// Buffer writes until headers are sent
|
|
972
1038
|
this._pendingWrites.push({ callback: () => callback(), chunk: buffer });
|
|
973
1039
|
// Auto-flush headers on first write
|
|
974
|
-
this.
|
|
1040
|
+
this._implicitHeader();
|
|
975
1041
|
}
|
|
976
1042
|
else {
|
|
977
1043
|
this._wrappedStream.write(buffer);
|
|
@@ -979,9 +1045,7 @@ class LambdaResponseStreaming extends node_stream.Writable {
|
|
|
979
1045
|
}
|
|
980
1046
|
}
|
|
981
1047
|
_final(callback) {
|
|
982
|
-
|
|
983
|
-
this.flushHeaders();
|
|
984
|
-
}
|
|
1048
|
+
this._implicitHeader();
|
|
985
1049
|
// For converted 204 responses, write empty JSON body
|
|
986
1050
|
// Lambda streaming requires body content for metadata to be transmitted
|
|
987
1051
|
if (this._convertedFrom204 && this._wrappedStream) {
|