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