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