@jaypie/express 1.2.31 → 1.2.33

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.
@@ -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
+ };
@@ -82,6 +82,7 @@ export interface ResponseStream {
82
82
  write(chunk: string | Uint8Array): void;
83
83
  }
84
84
  export interface HttpResponseStreamMetadata {
85
+ cookies?: string[];
85
86
  headers: Record<string, string>;
86
87
  statusCode: number;
87
88
  }
@@ -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
@@ -415,13 +459,14 @@ class LambdaResponseBuffered extends node_stream.Writable {
415
459
  return this;
416
460
  }
417
461
  const lowerName = name.toLowerCase();
418
- this._headers.set(lowerName, String(value));
462
+ const normalized = normalizeHeaderValue(value);
463
+ this._headers.set(lowerName, normalized);
419
464
  // Sync with kOutHeaders for dd-trace compatibility
420
465
  // Node stores as { 'header-name': ['Header-Name', value] }
421
466
  if (kOutHeaders$1) {
422
467
  const outHeaders = this[kOutHeaders$1];
423
468
  if (outHeaders) {
424
- outHeaders[lowerName] = [name, String(value)];
469
+ outHeaders[lowerName] = [name, normalized];
425
470
  }
426
471
  }
427
472
  return this;
@@ -509,7 +554,7 @@ class LambdaResponseBuffered extends node_stream.Writable {
509
554
  // Use direct _headers access to bypass dd-trace interception
510
555
  for (const [key, value] of Object.entries(headersToSet)) {
511
556
  if (value !== undefined) {
512
- this._headers.set(key.toLowerCase(), String(value));
557
+ this._headers.set(key.toLowerCase(), normalizeHeaderValue(value));
513
558
  }
514
559
  }
515
560
  }
@@ -537,7 +582,7 @@ class LambdaResponseBuffered extends node_stream.Writable {
537
582
  */
538
583
  set(name, value) {
539
584
  if (!this._headersSent) {
540
- this._headers.set(name.toLowerCase(), String(value));
585
+ this._headers.set(name.toLowerCase(), normalizeHeaderValue(value));
541
586
  }
542
587
  return this;
543
588
  }
@@ -607,23 +652,8 @@ class LambdaResponseBuffered extends node_stream.Writable {
607
652
  const contentType = this._headers.get("content-type") || "";
608
653
  // Determine if response should be base64 encoded
609
654
  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
- }
655
+ // Build headers object, carrying Set-Cookie out-of-band (v2 format)
656
+ const { cookies, headers } = splitCookieHeaders(this._headers);
627
657
  const result = {
628
658
  body: isBase64Encoded ? body.toString("base64") : body.toString("utf8"),
629
659
  headers,
@@ -756,13 +786,14 @@ class LambdaResponseStreaming extends node_stream.Writable {
756
786
  return this;
757
787
  }
758
788
  const lowerName = name.toLowerCase();
759
- this._headers.set(lowerName, String(value));
789
+ const normalized = normalizeHeaderValue(value);
790
+ this._headers.set(lowerName, normalized);
760
791
  // Sync with kOutHeaders for dd-trace compatibility
761
792
  // Node stores as { 'header-name': ['Header-Name', value] }
762
793
  if (kOutHeaders) {
763
794
  const outHeaders = this[kOutHeaders];
764
795
  if (outHeaders) {
765
- outHeaders[lowerName] = [name, String(value)];
796
+ outHeaders[lowerName] = [name, normalized];
766
797
  }
767
798
  }
768
799
  return this;
@@ -857,7 +888,7 @@ class LambdaResponseStreaming extends node_stream.Writable {
857
888
  // Use direct _headers access to bypass dd-trace interception
858
889
  for (const [key, value] of Object.entries(headersToSet)) {
859
890
  if (value !== undefined) {
860
- this._headers.set(key.toLowerCase(), String(value));
891
+ this._headers.set(key.toLowerCase(), normalizeHeaderValue(value));
861
892
  }
862
893
  }
863
894
  }
@@ -871,10 +902,8 @@ class LambdaResponseStreaming extends node_stream.Writable {
871
902
  if (this._headersSent) {
872
903
  return;
873
904
  }
874
- const headers = {};
875
- for (const [key, value] of this._headers) {
876
- headers[key] = Array.isArray(value) ? value.join(", ") : String(value);
877
- }
905
+ // Set-Cookie travels in metadata.cookies, never folded into headers
906
+ const { cookies, headers } = splitCookieHeaders(this._headers);
878
907
  // Lambda streaming requires body content for metadata to be transmitted.
879
908
  // Convert 204 No Content to 200 OK with empty JSON body as workaround.
880
909
  // See: https://github.com/finlaysonstudio/jaypie/issues/178
@@ -889,6 +918,10 @@ class LambdaResponseStreaming extends node_stream.Writable {
889
918
  headers,
890
919
  statusCode,
891
920
  };
921
+ // Only include cookies if present (v2 format)
922
+ if (cookies.length > 0) {
923
+ metadata.cookies = cookies;
924
+ }
892
925
  // Create wrapped stream with metadata
893
926
  this._wrappedStream = awslambda.HttpResponseStream.from(this._responseStream, metadata);
894
927
  this._headersSent = true;
@@ -917,7 +950,7 @@ class LambdaResponseStreaming extends node_stream.Writable {
917
950
  */
918
951
  set(name, value) {
919
952
  if (!this._headersSent) {
920
- this._headers.set(name.toLowerCase(), String(value));
953
+ this._headers.set(name.toLowerCase(), normalizeHeaderValue(value));
921
954
  }
922
955
  return this;
923
956
  }
@@ -1757,7 +1790,6 @@ function safeSend(res, statusCode, body) {
1757
1790
  }
1758
1791
  }
1759
1792
  function expressHandler(handlerOrOptions, optionsOrHandler) {
1760
- /* eslint-enable no-redeclare */
1761
1793
  let handler;
1762
1794
  let options;
1763
1795
  // If handler is an object and options is a function, swap them
@@ -2174,7 +2206,6 @@ function getErrorBody(error) {
2174
2206
  : new errors.UnhandledError().body();
2175
2207
  }
2176
2208
  function expressStreamHandler(handlerOrOptions, optionsOrHandler) {
2177
- /* eslint-enable no-redeclare */
2178
2209
  let handler;
2179
2210
  let options;
2180
2211
  // If handler is an object and options is a function, swap them