@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.
- package/dist/cjs/adapter/LambdaResponseBuffered.d.ts +1 -0
- package/dist/cjs/getCurrentInvokeUuid.adapter.d.ts +2 -2
- package/dist/cjs/index.cjs +32 -172
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.ts +0 -2
- package/dist/esm/adapter/LambdaResponseBuffered.d.ts +1 -0
- package/dist/esm/getCurrentInvokeUuid.adapter.d.ts +2 -2
- package/dist/esm/index.d.ts +0 -2
- package/dist/esm/index.js +32 -171
- package/dist/esm/index.js.map +1 -1
- package/package.json +2 -1
|
@@ -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
|
|
4
|
+
* Works with Jaypie Lambda adapter (createLambdaHandler/createLambdaStreamHandler).
|
|
5
5
|
*
|
|
6
6
|
* @param req - Optional Express request object. Used to extract context
|
|
7
|
-
* from
|
|
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;
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -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
|
|
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
|
|
1296
|
-
|
|
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
|
|
1171
|
+
* Works with Jaypie Lambda adapter (createLambdaHandler/createLambdaStreamHandler).
|
|
1307
1172
|
*
|
|
1308
1173
|
* @param req - Optional Express request object. Used to extract context
|
|
1309
|
-
* from
|
|
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:
|
|
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
|
|
1323
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
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 =
|
|
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;
|