@jaypie/express 1.2.11-dev.3 → 1.2.11-dev.5

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.
@@ -14,6 +14,7 @@ export declare class LambdaResponseStreaming extends Writable {
14
14
  };
15
15
  _headers: Map<string, string | string[]>;
16
16
  _headersSent: boolean;
17
+ private _convertedFrom204;
17
18
  private _pendingWrites;
18
19
  private _responseStream;
19
20
  private _wrappedStream;
@@ -654,6 +654,7 @@ class LambdaResponseStreaming extends node_stream.Writable {
654
654
  // that need to bypass dd-trace interception
655
655
  this._headers = new Map();
656
656
  this._headersSent = false;
657
+ this._convertedFrom204 = false;
657
658
  this._pendingWrites = [];
658
659
  this._wrappedStream = null;
659
660
  this._responseStream = responseStream;
@@ -661,10 +662,6 @@ class LambdaResponseStreaming extends node_stream.Writable {
661
662
  // Survives prototype manipulation from Express and dd-trace.
662
663
  this[JAYPIE_LAMBDA_STREAMING] =
663
664
  true;
664
- // DIAGNOSTIC: Log symbol assignment
665
- console.log("[DIAG:LambdaResponseStreaming:constructor] Symbol set", {
666
- symbolValue: this[JAYPIE_LAMBDA_STREAMING],
667
- });
668
665
  // Initialize Node's internal kOutHeaders for dd-trace compatibility.
669
666
  // dd-trace patches HTTP methods and expects this internal state.
670
667
  if (kOutHeaders) {
@@ -852,30 +849,28 @@ class LambdaResponseStreaming extends node_stream.Writable {
852
849
  return this._headersSent;
853
850
  }
854
851
  flushHeaders() {
855
- // DIAGNOSTIC: Log every flushHeaders call with stack trace
856
- const caller = new Error().stack?.split("\n").slice(1, 5).join("\n");
857
- console.log("[DIAG:LambdaResponseStreaming:flushHeaders] Called", {
858
- statusCode: this.statusCode,
859
- headersSent: this._headersSent,
860
- caller,
861
- });
862
852
  if (this._headersSent) {
863
- console.log("[DIAG:LambdaResponseStreaming:flushHeaders] Already sent, returning early");
864
853
  return;
865
854
  }
866
855
  const headers = {};
867
856
  for (const [key, value] of this._headers) {
868
857
  headers[key] = Array.isArray(value) ? value.join(", ") : String(value);
869
858
  }
859
+ // Lambda streaming requires body content for metadata to be transmitted.
860
+ // Convert 204 No Content to 200 OK with empty JSON body as workaround.
861
+ // See: https://github.com/finlaysonstudio/jaypie/issues/178
862
+ let statusCode = this.statusCode;
863
+ if (statusCode === 204) {
864
+ statusCode = 200;
865
+ this._convertedFrom204 = true;
866
+ // Set content-type for the JSON body we'll send
867
+ headers["content-type"] = "application/json";
868
+ }
870
869
  const metadata = {
871
870
  headers,
872
- statusCode: this.statusCode,
871
+ statusCode,
873
872
  };
874
- // DIAGNOSTIC: Log what we're sending to Lambda
875
- console.log("[DIAG:LambdaResponseStreaming:flushHeaders] Creating wrapped stream", {
876
- metadata,
877
- });
878
- // Wrap the stream with metadata using awslambda global
873
+ // Create wrapped stream with metadata
879
874
  this._wrappedStream = awslambda.HttpResponseStream.from(this._responseStream, metadata);
880
875
  this._headersSent = true;
881
876
  // Flush pending writes
@@ -908,14 +903,6 @@ class LambdaResponseStreaming extends node_stream.Writable {
908
903
  return this;
909
904
  }
910
905
  status(code) {
911
- // DIAGNOSTIC: Log status code changes
912
- const caller = new Error().stack?.split("\n").slice(1, 4).join("\n");
913
- console.log("[DIAG:LambdaResponseStreaming:status] Setting status", {
914
- newCode: code,
915
- previousCode: this.statusCode,
916
- headersSent: this._headersSent,
917
- caller,
918
- });
919
906
  this.statusCode = code;
920
907
  return this;
921
908
  }
@@ -961,17 +948,10 @@ class LambdaResponseStreaming extends node_stream.Writable {
961
948
  const buffer = Buffer.isBuffer(chunk)
962
949
  ? chunk
963
950
  : Buffer.from(chunk, encoding);
964
- // DIAGNOSTIC: Log every write
965
- console.log("[DIAG:LambdaResponseStreaming:_write] Called", {
966
- chunkLength: buffer.length,
967
- headersSent: this._headersSent,
968
- statusCode: this.statusCode,
969
- });
970
951
  if (!this._headersSent) {
971
952
  // Buffer writes until headers are sent
972
953
  this._pendingWrites.push({ callback: () => callback(), chunk: buffer });
973
954
  // Auto-flush headers on first write
974
- console.log("[DIAG:LambdaResponseStreaming:_write] Auto-flushing headers on first write");
975
955
  this.flushHeaders();
976
956
  }
977
957
  else {
@@ -980,21 +960,15 @@ class LambdaResponseStreaming extends node_stream.Writable {
980
960
  }
981
961
  }
982
962
  _final(callback) {
983
- // DIAGNOSTIC: Log _final call
984
- console.log("[DIAG:LambdaResponseStreaming:_final] Called", {
985
- headersSent: this._headersSent,
986
- statusCode: this.statusCode,
987
- hasWrappedStream: !!this._wrappedStream,
988
- });
989
963
  if (!this._headersSent) {
990
- console.log("[DIAG:LambdaResponseStreaming:_final] Headers not sent, flushing now");
991
964
  this.flushHeaders();
992
965
  }
966
+ // For converted 204 responses, write empty JSON body
967
+ // Lambda streaming requires body content for metadata to be transmitted
968
+ if (this._convertedFrom204 && this._wrappedStream) {
969
+ this._wrappedStream.write("{}");
970
+ }
993
971
  if (this._wrappedStream) {
994
- // FIX #178: Write empty chunk to force Lambda to process metadata
995
- // Without this, 204 responses have no writes and Lambda ignores our statusCode/headers
996
- console.log("[DIAG:LambdaResponseStreaming:_final] Writing empty chunk for metadata");
997
- this._wrappedStream.write("");
998
972
  this._wrappedStream.end();
999
973
  }
1000
974
  // Use setImmediate to ensure stream operations complete before callback
@@ -1507,8 +1481,7 @@ const decorateResponse = (res, { handler = "", version = process.env.PROJECT_VER
1507
1481
  // X-Powered-By, override "Express" but nothing else
1508
1482
  const currentPoweredBy = safeGetHeader(extRes, kit.HTTP.HEADER.POWERED_BY);
1509
1483
  if (!currentPoweredBy || currentPoweredBy === "Express") {
1510
- // DIAGNOSTIC: Include dev marker to verify build deployment
1511
- safeSetHeader(extRes, kit.HTTP.HEADER.POWERED_BY, `${kit.JAYPIE.LIB.EXPRESS}@1.2.11-dev`);
1484
+ safeSetHeader(extRes, kit.HTTP.HEADER.POWERED_BY, kit.JAYPIE.LIB.EXPRESS);
1512
1485
  }
1513
1486
  // X-Project-Environment
1514
1487
  if (process.env.PROJECT_ENV) {
@@ -1605,16 +1578,8 @@ function isLambdaMockResponse(res) {
1605
1578
  * Uses Symbol marker to survive prototype chain modifications from Express and dd-trace.
1606
1579
  */
1607
1580
  function isLambdaStreamingResponse(res) {
1608
- const symbolValue = res[JAYPIE_LAMBDA_STREAMING];
1609
- const result = symbolValue === true;
1610
- // DIAGNOSTIC: Log symbol check
1611
- console.log("[DIAG:expressHandler:isLambdaStreamingResponse] Check", {
1612
- symbolValue,
1613
- result,
1614
- resConstructorName: res?.constructor?.name,
1615
- hasFlushHeaders: typeof res.flushHeaders === "function",
1616
- });
1617
- return result;
1581
+ return (res[JAYPIE_LAMBDA_STREAMING] ===
1582
+ true);
1618
1583
  }
1619
1584
  /**
1620
1585
  * Safely send a JSON response, avoiding dd-trace interception.
@@ -1643,34 +1608,19 @@ function safeSendJson(res, statusCode, data) {
1643
1608
  res._resolve(res.buildResult());
1644
1609
  }
1645
1610
  // Emit "finish" event so runExpressApp's promise resolves
1646
- console.log("[safeSendJson] Emitting finish event");
1647
1611
  res.emit("finish");
1648
1612
  return;
1649
1613
  }
1650
1614
  // Fall back to standard Express methods for real responses
1651
- // DIAGNOSTIC: Log before setting status
1652
- console.log("[DIAG:expressHandler:safeSendJson] Before res.status()", {
1653
- statusCode,
1654
- currentStatusCode: res.statusCode,
1655
- });
1656
1615
  res.status(statusCode);
1657
- console.log("[DIAG:expressHandler:safeSendJson] After res.status()", {
1658
- statusCode,
1659
- newStatusCode: res.statusCode,
1660
- });
1661
1616
  // CRITICAL: For Lambda streaming responses, flush headers before send to
1662
1617
  // initialize the stream wrapper. This ensures the status code is captured
1663
1618
  // before any writes occur (which would auto-flush with default 200).
1664
1619
  // Uses Symbol marker for reliable detection that survives prototype manipulation.
1665
- const isStreaming = isLambdaStreamingResponse(res);
1666
- console.log("[DIAG:expressHandler:safeSendJson] Streaming check", {
1667
- isStreaming,
1668
- });
1669
- if (isStreaming && typeof res.flushHeaders === "function") {
1670
- console.log("[DIAG:expressHandler:safeSendJson] Calling flushHeaders explicitly");
1620
+ if (isLambdaStreamingResponse(res) &&
1621
+ typeof res.flushHeaders === "function") {
1671
1622
  res.flushHeaders();
1672
1623
  }
1673
- console.log("[DIAG:expressHandler:safeSendJson] Calling res.json()");
1674
1624
  res.json(data);
1675
1625
  }
1676
1626
  /**
@@ -1694,40 +1644,23 @@ function safeSend(res, statusCode, body) {
1694
1644
  res._resolve(res.buildResult());
1695
1645
  }
1696
1646
  // Emit "finish" event so runExpressApp's promise resolves
1697
- console.log("[safeSend] Emitting finish event");
1698
1647
  res.emit("finish");
1699
1648
  return;
1700
1649
  }
1701
1650
  // Fall back to standard Express methods for real responses
1702
- // DIAGNOSTIC: Log before setting status
1703
- console.log("[DIAG:expressHandler:safeSend] Before res.status()", {
1704
- statusCode,
1705
- currentStatusCode: res.statusCode,
1706
- hasBody: body !== undefined,
1707
- });
1708
1651
  res.status(statusCode);
1709
- console.log("[DIAG:expressHandler:safeSend] After res.status()", {
1710
- statusCode,
1711
- newStatusCode: res.statusCode,
1712
- });
1713
1652
  // CRITICAL: For Lambda streaming responses, flush headers before send to
1714
1653
  // initialize the stream wrapper. This ensures the status code is captured
1715
1654
  // before any writes occur (which would auto-flush with default 200).
1716
1655
  // Uses Symbol marker for reliable detection that survives prototype manipulation.
1717
- const isStreaming = isLambdaStreamingResponse(res);
1718
- console.log("[DIAG:expressHandler:safeSend] Streaming check", {
1719
- isStreaming,
1720
- });
1721
- if (isStreaming && typeof res.flushHeaders === "function") {
1722
- console.log("[DIAG:expressHandler:safeSend] Calling flushHeaders explicitly");
1656
+ if (isLambdaStreamingResponse(res) &&
1657
+ typeof res.flushHeaders === "function") {
1723
1658
  res.flushHeaders();
1724
1659
  }
1725
1660
  if (body !== undefined) {
1726
- console.log("[DIAG:expressHandler:safeSend] Calling res.send(body)");
1727
1661
  res.send(body);
1728
1662
  }
1729
1663
  else {
1730
- console.log("[DIAG:expressHandler:safeSend] Calling res.send() (no body)");
1731
1664
  res.send();
1732
1665
  }
1733
1666
  }