@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/cjs/index.cjs
CHANGED
|
@@ -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
|
|
871
|
+
statusCode,
|
|
873
872
|
};
|
|
874
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
1609
|
-
|
|
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
|
-
|
|
1666
|
-
|
|
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
|
-
|
|
1718
|
-
|
|
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
|
}
|