@jaypie/express 1.2.4-rc22 → 1.2.4-rc24

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 { LambdaResponse } from "./types.js";
4
+ export declare const JAYPIE_LAMBDA_MOCK: unique symbol;
4
5
  /**
5
6
  * Mock ServerResponse that buffers the response.
6
7
  * Collects status, headers, and body chunks, then returns a Lambda response.
@@ -1,10 +1,10 @@
1
1
  import type { Request } from "express";
2
2
  /**
3
3
  * Get the current invoke UUID from Lambda context.
4
- * Works with Jaypie Lambda adapter and Lambda Web Adapter mode.
4
+ * Works with Jaypie Lambda adapter (createLambdaHandler/createLambdaStreamHandler).
5
5
  *
6
6
  * @param req - Optional Express request object. Used to extract context
7
- * from Web Adapter headers or Jaypie adapter's _lambdaContext.
7
+ * from Jaypie adapter's _lambdaContext.
8
8
  * @returns The AWS request ID or undefined if not in Lambda context
9
9
  */
10
10
  declare function getCurrentInvokeUuid(req?: Request): string | undefined;
@@ -5,8 +5,8 @@ var node_http = require('node:http');
5
5
  var errors = require('@jaypie/errors');
6
6
  var kit = require('@jaypie/kit');
7
7
  var expressCors = require('cors');
8
- var logger$2 = require('@jaypie/logger');
9
8
  var aws = require('@jaypie/aws');
9
+ var logger$2 = require('@jaypie/logger');
10
10
  var datadog = require('@jaypie/datadog');
11
11
 
12
12
  //
@@ -188,6 +188,9 @@ function createLambdaRequest(event, context) {
188
188
  //
189
189
  // Constants
190
190
  //
191
+ // Symbol to identify Lambda mock responses. Uses Symbol.for() to ensure
192
+ // the same symbol is used across bundles/realms. Survives prototype manipulation.
193
+ const JAYPIE_LAMBDA_MOCK = Symbol.for("@jaypie/express/LambdaMock");
191
194
  // Get Node's internal kOutHeaders symbol from ServerResponse prototype.
192
195
  // This is needed for compatibility with Datadog dd-trace instrumentation,
193
196
  // which patches HTTP methods and expects this internal state to exist.
@@ -225,6 +228,8 @@ class LambdaResponseBuffered extends node_stream.Writable {
225
228
  this._headers = new Map();
226
229
  this._headersSent = false;
227
230
  this._resolve = null;
231
+ // Mark as Lambda mock response for identification in expressHandler
232
+ this[JAYPIE_LAMBDA_MOCK] = true;
228
233
  // Initialize Node's internal kOutHeaders for dd-trace compatibility.
229
234
  // dd-trace patches HTTP methods and expects this internal state.
230
235
  if (kOutHeaders$1) {
@@ -1113,7 +1118,7 @@ const corsHelper = (config = {}) => {
1113
1118
  };
1114
1119
  return expressCors(options);
1115
1120
  };
1116
- var cors = (config) => {
1121
+ var cors_helper = (config) => {
1117
1122
  const cors = corsHelper(config);
1118
1123
  return (req, res, next) => {
1119
1124
  cors(req, res, (error) => {
@@ -1128,154 +1133,10 @@ var cors = (config) => {
1128
1133
  };
1129
1134
  };
1130
1135
 
1131
- //
1132
- //
1133
- // Constants
1134
- //
1135
- const DEFAULT_PORT = 8080;
1136
- //
1137
- //
1138
- // Main
1139
- //
1140
- /**
1141
- * Creates and starts an Express server with standard Jaypie middleware.
1142
- *
1143
- * Features:
1144
- * - CORS handling (configurable)
1145
- * - JSON body parsing
1146
- * - Listens on PORT env var (default 8080)
1147
- *
1148
- * Usage:
1149
- * ```ts
1150
- * import express from "express";
1151
- * import { createServer, expressHandler } from "@jaypie/express";
1152
- *
1153
- * const app = express();
1154
- *
1155
- * app.get("/", expressHandler(async (req, res) => {
1156
- * return { message: "Hello World" };
1157
- * }));
1158
- *
1159
- * const { server, port } = await createServer(app);
1160
- * console.log(`Server running on port ${port}`);
1161
- * ```
1162
- *
1163
- * @param app - Express application instance
1164
- * @param options - Server configuration options
1165
- * @returns Promise resolving to server instance and port
1166
- */
1167
- async function createServer(app, options = {}) {
1168
- const { cors: corsConfig, jsonLimit = "1mb", middleware = [], port: portOption, } = options;
1169
- // Determine port
1170
- const port = typeof portOption === "string"
1171
- ? parseInt(portOption, 10)
1172
- : (portOption ?? parseInt(process.env.PORT || String(DEFAULT_PORT), 10));
1173
- // Apply CORS middleware (unless explicitly disabled)
1174
- if (corsConfig !== false) {
1175
- app.use(cors(corsConfig));
1176
- }
1177
- // Apply JSON body parser
1178
- // Note: We use dynamic import to avoid requiring express as a direct dependency
1179
- const express = await import('express');
1180
- app.use(express.json({ limit: jsonLimit }));
1181
- // Apply additional middleware
1182
- for (const mw of middleware) {
1183
- app.use(mw);
1184
- }
1185
- // Start server
1186
- return new Promise((resolve, reject) => {
1187
- try {
1188
- const server = app.listen(port, () => {
1189
- // Get the actual port (important when port 0 is passed to get an ephemeral port)
1190
- const address = server.address();
1191
- const actualPort = address?.port ?? port;
1192
- logger$2.log.info(`Server listening on port ${actualPort}`);
1193
- resolve({ port: actualPort, server });
1194
- });
1195
- server.on("error", (error) => {
1196
- logger$2.log.error("Server error", { error });
1197
- reject(error);
1198
- });
1199
- }
1200
- catch (error) {
1201
- reject(error);
1202
- }
1203
- });
1204
- }
1205
-
1206
- //
1207
- //
1208
- // Constants
1209
- //
1210
- const HEADER_AMZN_REQUEST_ID$1 = "x-amzn-request-id";
1211
- const ENV_AMZN_TRACE_ID = "_X_AMZN_TRACE_ID";
1212
1136
  //
1213
1137
  //
1214
1138
  // Helper Functions
1215
1139
  //
1216
- /**
1217
- * Extract request ID from X-Ray trace ID environment variable
1218
- * Format: Root=1-5e6b4a90-example;Parent=example;Sampled=1
1219
- * We extract the trace ID from the Root segment
1220
- */
1221
- function parseTraceId(traceId) {
1222
- if (!traceId)
1223
- return undefined;
1224
- // Extract the Root segment (format: Root=1-{timestamp}-{uuid})
1225
- const rootMatch = traceId.match(/Root=([^;]+)/);
1226
- if (rootMatch && rootMatch[1]) {
1227
- return rootMatch[1];
1228
- }
1229
- return undefined;
1230
- }
1231
- //
1232
- //
1233
- // Main
1234
- //
1235
- /**
1236
- * Get the current invoke UUID from Lambda Web Adapter context.
1237
- * This function extracts the request ID from either:
1238
- * 1. The x-amzn-request-id header (set by Lambda Web Adapter)
1239
- * 2. The _X_AMZN_TRACE_ID environment variable (set by Lambda runtime)
1240
- *
1241
- * @param req - Optional Express request object to extract headers from
1242
- * @returns The AWS request ID or undefined if not in Lambda context
1243
- */
1244
- function getWebAdapterUuid(req) {
1245
- // First, try to get from request headers
1246
- if (req && req.headers) {
1247
- const headerValue = req.headers[HEADER_AMZN_REQUEST_ID$1];
1248
- if (headerValue) {
1249
- return Array.isArray(headerValue) ? headerValue[0] : headerValue;
1250
- }
1251
- }
1252
- // Fall back to environment variable (X-Ray trace ID)
1253
- const traceId = process.env[ENV_AMZN_TRACE_ID];
1254
- if (traceId) {
1255
- return parseTraceId(traceId);
1256
- }
1257
- return undefined;
1258
- }
1259
-
1260
- //
1261
- //
1262
- // Constants
1263
- //
1264
- const HEADER_AMZN_REQUEST_ID = "x-amzn-request-id";
1265
- //
1266
- //
1267
- // Helper Functions
1268
- //
1269
- /**
1270
- * Detect if we're running in Lambda Web Adapter mode.
1271
- * Web Adapter sets the x-amzn-request-id header on requests.
1272
- */
1273
- function isWebAdapterMode(req) {
1274
- if (req && req.headers && req.headers[HEADER_AMZN_REQUEST_ID]) {
1275
- return true;
1276
- }
1277
- return false;
1278
- }
1279
1140
  /**
1280
1141
  * Get UUID from Jaypie Lambda adapter context.
1281
1142
  * This is set by createLambdaHandler/createLambdaStreamHandler.
@@ -1292,8 +1153,12 @@ function getJaypieAdapterUuid() {
1292
1153
  * The Jaypie adapter attaches _lambdaContext to the request.
1293
1154
  */
1294
1155
  function getRequestContextUuid(req) {
1295
- if (req && req._lambdaContext?.awsRequestId) {
1296
- return req._lambdaContext.awsRequestId;
1156
+ if (req && req._lambdaContext) {
1157
+ const lambdaContext = req
1158
+ ._lambdaContext;
1159
+ if (lambdaContext.awsRequestId) {
1160
+ return lambdaContext.awsRequestId;
1161
+ }
1297
1162
  }
1298
1163
  return undefined;
1299
1164
  }
@@ -1303,29 +1168,20 @@ function getRequestContextUuid(req) {
1303
1168
  //
1304
1169
  /**
1305
1170
  * Get the current invoke UUID from Lambda context.
1306
- * Works with Jaypie Lambda adapter and Lambda Web Adapter mode.
1171
+ * Works with Jaypie Lambda adapter (createLambdaHandler/createLambdaStreamHandler).
1307
1172
  *
1308
1173
  * @param req - Optional Express request object. Used to extract context
1309
- * from Web Adapter headers or Jaypie adapter's _lambdaContext.
1174
+ * from Jaypie adapter's _lambdaContext.
1310
1175
  * @returns The AWS request ID or undefined if not in Lambda context
1311
1176
  */
1312
1177
  function getCurrentInvokeUuid(req) {
1313
- // Priority 1: Web Adapter mode (header-based)
1314
- if (isWebAdapterMode(req)) {
1315
- return getWebAdapterUuid(req);
1316
- }
1317
- // Priority 2: Request has Lambda context attached (Jaypie adapter)
1178
+ // Priority 1: Request has Lambda context attached (Jaypie adapter)
1318
1179
  const requestContextUuid = getRequestContextUuid(req);
1319
1180
  if (requestContextUuid) {
1320
1181
  return requestContextUuid;
1321
1182
  }
1322
- // Priority 3: Global context from Jaypie adapter
1323
- const jaypieAdapterUuid = getJaypieAdapterUuid();
1324
- if (jaypieAdapterUuid) {
1325
- return jaypieAdapterUuid;
1326
- }
1327
- // Fallback: Web Adapter env var
1328
- return getWebAdapterUuid();
1183
+ // Priority 2: Global context from Jaypie adapter
1184
+ return getJaypieAdapterUuid();
1329
1185
  }
1330
1186
 
1331
1187
  //
@@ -1507,12 +1363,10 @@ const logger$1 = logger$2.log;
1507
1363
  //
1508
1364
  /**
1509
1365
  * Check if response is a Lambda mock response with direct internal access.
1366
+ * Uses Symbol marker to survive prototype chain modifications from Express and dd-trace.
1510
1367
  */
1511
1368
  function isLambdaMockResponse(res) {
1512
- const mock = res;
1513
- return (mock._headers instanceof Map &&
1514
- Array.isArray(mock._chunks) &&
1515
- typeof mock.buildResult === "function");
1369
+ return res[JAYPIE_LAMBDA_MOCK] === true;
1516
1370
  }
1517
1371
  /**
1518
1372
  * Safely send a JSON response, avoiding dd-trace interception.
@@ -1838,10 +1692,17 @@ function expressHandler(handlerOrOptions, optionsOrHandler) {
1838
1692
  }
1839
1693
  catch (error) {
1840
1694
  // Use console.error for raw stack trace to ensure it appears in CloudWatch
1841
- if (error instanceof Error) {
1842
- console.error("Express response error stack trace:", error.stack);
1843
- }
1844
- log.fatal(`Express encountered an error while sending the response: ${error instanceof Error ? error.message : String(error)}`);
1695
+ // Handle both Error objects and plain thrown values
1696
+ const errorMessage = error instanceof Error
1697
+ ? error.message
1698
+ : typeof error === "object" && error !== null
1699
+ ? JSON.stringify(error)
1700
+ : String(error);
1701
+ const errorStack = error instanceof Error
1702
+ ? error.stack
1703
+ : new Error("Stack trace").stack?.replace("Error: Stack trace", `Error: ${errorMessage}`);
1704
+ console.error("Express response error stack trace:", errorStack);
1705
+ log.fatal(`Express encountered an error while sending the response: ${errorMessage}`);
1845
1706
  log.var({ responseError: error });
1846
1707
  }
1847
1708
  // Log response
@@ -2222,10 +2083,9 @@ exports.LambdaRequest = LambdaRequest;
2222
2083
  exports.LambdaResponseBuffered = LambdaResponseBuffered;
2223
2084
  exports.LambdaResponseStreaming = LambdaResponseStreaming;
2224
2085
  exports.badRequestRoute = badRequestRoute;
2225
- exports.cors = cors;
2086
+ exports.cors = cors_helper;
2226
2087
  exports.createLambdaHandler = createLambdaHandler;
2227
2088
  exports.createLambdaStreamHandler = createLambdaStreamHandler;
2228
- exports.createServer = createServer;
2229
2089
  exports.echoRoute = echoRoute;
2230
2090
  exports.expressHandler = expressHandler;
2231
2091
  exports.expressHttpCodeHandler = httpHandler;