@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.
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
|
|
869
|
+
statusCode,
|
|
871
870
|
};
|
|
872
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
1607
|
-
|
|
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
|
-
|
|
1664
|
-
|
|
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
|
-
|
|
1716
|
-
|
|
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
|
}
|