@jaypie/express 1.2.9 → 1.2.11-dev.0

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.
@@ -1,6 +1,7 @@
1
1
  import type { OutgoingHttpHeaders } from "node:http";
2
2
  import { Writable } from "node:stream";
3
3
  import type { ResponseStream } from "./types.js";
4
+ export declare const JAYPIE_LAMBDA_STREAMING: unique symbol;
4
5
  /**
5
6
  * Mock ServerResponse that streams directly to Lambda responseStream.
6
7
  * Uses awslambda.HttpResponseStream.from() to set status and headers.
@@ -626,6 +626,9 @@ class LambdaResponseBuffered extends node_stream.Writable {
626
626
  //
627
627
  // Constants
628
628
  //
629
+ // Symbol to identify Lambda streaming responses. Uses Symbol.for() to ensure
630
+ // the same symbol is used across bundles/realms. Survives prototype manipulation.
631
+ const JAYPIE_LAMBDA_STREAMING = Symbol.for("@jaypie/express/LambdaStreaming");
629
632
  // Get Node's internal kOutHeaders symbol from ServerResponse prototype.
630
633
  // This is needed for compatibility with Datadog dd-trace instrumentation,
631
634
  // which patches HTTP methods and expects this internal state to exist.
@@ -654,6 +657,14 @@ class LambdaResponseStreaming extends node_stream.Writable {
654
657
  this._pendingWrites = [];
655
658
  this._wrappedStream = null;
656
659
  this._responseStream = responseStream;
660
+ // Mark as Lambda streaming response using Symbol for reliable detection.
661
+ // Survives prototype manipulation from Express and dd-trace.
662
+ this[JAYPIE_LAMBDA_STREAMING] =
663
+ true;
664
+ // DIAGNOSTIC: Log symbol assignment
665
+ console.log("[DIAG:LambdaResponseStreaming:constructor] Symbol set", {
666
+ symbolValue: this[JAYPIE_LAMBDA_STREAMING],
667
+ });
657
668
  // Initialize Node's internal kOutHeaders for dd-trace compatibility.
658
669
  // dd-trace patches HTTP methods and expects this internal state.
659
670
  if (kOutHeaders) {
@@ -841,8 +852,17 @@ class LambdaResponseStreaming extends node_stream.Writable {
841
852
  return this._headersSent;
842
853
  }
843
854
  flushHeaders() {
844
- if (this._headersSent)
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
+ if (this._headersSent) {
863
+ console.log("[DIAG:LambdaResponseStreaming:flushHeaders] Already sent, returning early");
845
864
  return;
865
+ }
846
866
  const headers = {};
847
867
  for (const [key, value] of this._headers) {
848
868
  headers[key] = Array.isArray(value) ? value.join(", ") : String(value);
@@ -851,6 +871,10 @@ class LambdaResponseStreaming extends node_stream.Writable {
851
871
  headers,
852
872
  statusCode: this.statusCode,
853
873
  };
874
+ // DIAGNOSTIC: Log what we're sending to Lambda
875
+ console.log("[DIAG:LambdaResponseStreaming:flushHeaders] Creating wrapped stream", {
876
+ metadata,
877
+ });
854
878
  // Wrap the stream with metadata using awslambda global
855
879
  this._wrappedStream = awslambda.HttpResponseStream.from(this._responseStream, metadata);
856
880
  this._headersSent = true;
@@ -884,6 +908,14 @@ class LambdaResponseStreaming extends node_stream.Writable {
884
908
  return this;
885
909
  }
886
910
  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
+ });
887
919
  this.statusCode = code;
888
920
  return this;
889
921
  }
@@ -929,10 +961,17 @@ class LambdaResponseStreaming extends node_stream.Writable {
929
961
  const buffer = Buffer.isBuffer(chunk)
930
962
  ? chunk
931
963
  : 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
+ });
932
970
  if (!this._headersSent) {
933
971
  // Buffer writes until headers are sent
934
972
  this._pendingWrites.push({ callback: () => callback(), chunk: buffer });
935
973
  // Auto-flush headers on first write
974
+ console.log("[DIAG:LambdaResponseStreaming:_write] Auto-flushing headers on first write");
936
975
  this.flushHeaders();
937
976
  }
938
977
  else {
@@ -941,7 +980,14 @@ class LambdaResponseStreaming extends node_stream.Writable {
941
980
  }
942
981
  }
943
982
  _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
+ });
944
989
  if (!this._headersSent) {
990
+ console.log("[DIAG:LambdaResponseStreaming:_final] Headers not sent, flushing now");
945
991
  this.flushHeaders();
946
992
  }
947
993
  this._wrappedStream?.end();
@@ -1026,13 +1072,6 @@ function createLambdaHandler(app, _options) {
1026
1072
  await runExpressApp(app, req, res);
1027
1073
  // Get Lambda response - await explicitly to ensure we have the result
1028
1074
  result = await res.getResult();
1029
- // Debug: Log the response before returning
1030
- console.log("[createLambdaHandler] Returning response:", JSON.stringify({
1031
- statusCode: result.statusCode,
1032
- headers: result.headers,
1033
- bodyLength: result.body?.length,
1034
- isBase64Encoded: result.isBase64Encoded,
1035
- }));
1036
1075
  return result;
1037
1076
  }
1038
1077
  catch (error) {
@@ -1461,7 +1500,8 @@ const decorateResponse = (res, { handler = "", version = process.env.PROJECT_VER
1461
1500
  // X-Powered-By, override "Express" but nothing else
1462
1501
  const currentPoweredBy = safeGetHeader(extRes, kit.HTTP.HEADER.POWERED_BY);
1463
1502
  if (!currentPoweredBy || currentPoweredBy === "Express") {
1464
- safeSetHeader(extRes, kit.HTTP.HEADER.POWERED_BY, kit.JAYPIE.LIB.EXPRESS);
1503
+ // DIAGNOSTIC: Include dev marker to verify build deployment
1504
+ safeSetHeader(extRes, kit.HTTP.HEADER.POWERED_BY, `${kit.JAYPIE.LIB.EXPRESS}#dev-178`);
1465
1505
  }
1466
1506
  // X-Project-Environment
1467
1507
  if (process.env.PROJECT_ENV) {
@@ -1553,6 +1593,22 @@ const logger$1 = logger$2.log;
1553
1593
  function isLambdaMockResponse(res) {
1554
1594
  return (res[JAYPIE_LAMBDA_MOCK] === true);
1555
1595
  }
1596
+ /**
1597
+ * Check if response is a Lambda streaming response.
1598
+ * Uses Symbol marker to survive prototype chain modifications from Express and dd-trace.
1599
+ */
1600
+ function isLambdaStreamingResponse(res) {
1601
+ const symbolValue = res[JAYPIE_LAMBDA_STREAMING];
1602
+ const result = symbolValue === true;
1603
+ // DIAGNOSTIC: Log symbol check
1604
+ console.log("[DIAG:expressHandler:isLambdaStreamingResponse] Check", {
1605
+ symbolValue,
1606
+ result,
1607
+ resConstructorName: res?.constructor?.name,
1608
+ hasFlushHeaders: typeof res.flushHeaders === "function",
1609
+ });
1610
+ return result;
1611
+ }
1556
1612
  /**
1557
1613
  * Safely send a JSON response, avoiding dd-trace interception.
1558
1614
  * For Lambda mock responses, directly manipulates internal state instead of
@@ -1585,13 +1641,29 @@ function safeSendJson(res, statusCode, data) {
1585
1641
  return;
1586
1642
  }
1587
1643
  // Fall back to standard Express methods for real responses
1644
+ // DIAGNOSTIC: Log before setting status
1645
+ console.log("[DIAG:expressHandler:safeSendJson] Before res.status()", {
1646
+ statusCode,
1647
+ currentStatusCode: res.statusCode,
1648
+ });
1588
1649
  res.status(statusCode);
1650
+ console.log("[DIAG:expressHandler:safeSendJson] After res.status()", {
1651
+ statusCode,
1652
+ newStatusCode: res.statusCode,
1653
+ });
1589
1654
  // CRITICAL: For Lambda streaming responses, flush headers before send to
1590
- // initialize the stream wrapper. Check for _responseStream which is unique
1591
- // to LambdaResponseStreaming (regular Express res doesn't have this).
1592
- if ("_responseStream" in res && typeof res.flushHeaders === "function") {
1655
+ // initialize the stream wrapper. This ensures the status code is captured
1656
+ // before any writes occur (which would auto-flush with default 200).
1657
+ // Uses Symbol marker for reliable detection that survives prototype manipulation.
1658
+ const isStreaming = isLambdaStreamingResponse(res);
1659
+ console.log("[DIAG:expressHandler:safeSendJson] Streaming check", {
1660
+ isStreaming,
1661
+ });
1662
+ if (isStreaming && typeof res.flushHeaders === "function") {
1663
+ console.log("[DIAG:expressHandler:safeSendJson] Calling flushHeaders explicitly");
1593
1664
  res.flushHeaders();
1594
1665
  }
1666
+ console.log("[DIAG:expressHandler:safeSendJson] Calling res.json()");
1595
1667
  res.json(data);
1596
1668
  }
1597
1669
  /**
@@ -1620,17 +1692,35 @@ function safeSend(res, statusCode, body) {
1620
1692
  return;
1621
1693
  }
1622
1694
  // Fall back to standard Express methods for real responses
1695
+ // DIAGNOSTIC: Log before setting status
1696
+ console.log("[DIAG:expressHandler:safeSend] Before res.status()", {
1697
+ statusCode,
1698
+ currentStatusCode: res.statusCode,
1699
+ hasBody: body !== undefined,
1700
+ });
1623
1701
  res.status(statusCode);
1702
+ console.log("[DIAG:expressHandler:safeSend] After res.status()", {
1703
+ statusCode,
1704
+ newStatusCode: res.statusCode,
1705
+ });
1624
1706
  // CRITICAL: For Lambda streaming responses, flush headers before send to
1625
- // initialize the stream wrapper. Check for _responseStream which is unique
1626
- // to LambdaResponseStreaming (regular Express res doesn't have this).
1627
- if ("_responseStream" in res && typeof res.flushHeaders === "function") {
1707
+ // initialize the stream wrapper. This ensures the status code is captured
1708
+ // before any writes occur (which would auto-flush with default 200).
1709
+ // Uses Symbol marker for reliable detection that survives prototype manipulation.
1710
+ const isStreaming = isLambdaStreamingResponse(res);
1711
+ console.log("[DIAG:expressHandler:safeSend] Streaming check", {
1712
+ isStreaming,
1713
+ });
1714
+ if (isStreaming && typeof res.flushHeaders === "function") {
1715
+ console.log("[DIAG:expressHandler:safeSend] Calling flushHeaders explicitly");
1628
1716
  res.flushHeaders();
1629
1717
  }
1630
1718
  if (body !== undefined) {
1719
+ console.log("[DIAG:expressHandler:safeSend] Calling res.send(body)");
1631
1720
  res.send(body);
1632
1721
  }
1633
1722
  else {
1723
+ console.log("[DIAG:expressHandler:safeSend] Calling res.send() (no body)");
1634
1724
  res.send();
1635
1725
  }
1636
1726
  }