@jaypie/express 1.2.2 → 1.2.3

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.
@@ -0,0 +1,60 @@
1
+ import type { Application, RequestHandler } from "express";
2
+ import type { Server } from "http";
3
+ import type { CorsConfig } from "./cors.helper.js";
4
+ export interface CreateServerOptions {
5
+ /**
6
+ * CORS configuration. Pass false to disable CORS middleware.
7
+ */
8
+ cors?: CorsConfig | false;
9
+ /**
10
+ * JSON body parser limit. Defaults to "1mb".
11
+ */
12
+ jsonLimit?: string;
13
+ /**
14
+ * Additional middleware to apply before routes.
15
+ */
16
+ middleware?: RequestHandler[];
17
+ /**
18
+ * Port to listen on. Defaults to PORT env var or 8080.
19
+ */
20
+ port?: number | string;
21
+ }
22
+ export interface ServerResult {
23
+ /**
24
+ * The HTTP server instance.
25
+ */
26
+ server: Server;
27
+ /**
28
+ * The port the server is listening on.
29
+ */
30
+ port: number;
31
+ }
32
+ /**
33
+ * Creates and starts an Express server with standard Jaypie middleware.
34
+ *
35
+ * Features:
36
+ * - CORS handling (configurable)
37
+ * - JSON body parsing
38
+ * - Listens on PORT env var (default 8080)
39
+ *
40
+ * Usage:
41
+ * ```ts
42
+ * import express from "express";
43
+ * import { createServer, expressHandler } from "@jaypie/express";
44
+ *
45
+ * const app = express();
46
+ *
47
+ * app.get("/", expressHandler(async (req, res) => {
48
+ * return { message: "Hello World" };
49
+ * }));
50
+ *
51
+ * const { server, port } = await createServer(app);
52
+ * console.log(`Server running on port ${port}`);
53
+ * ```
54
+ *
55
+ * @param app - Express application instance
56
+ * @param options - Server configuration options
57
+ * @returns Promise resolving to server instance and port
58
+ */
59
+ declare function createServer(app: Application, options?: CreateServerOptions): Promise<ServerResult>;
60
+ export default createServer;
@@ -1,2 +1,11 @@
1
- declare const getCurrentInvokeUuid: () => string | undefined;
1
+ import type { Request } from "express";
2
+ /**
3
+ * Get the current invoke UUID from Lambda context.
4
+ * Works in both serverless-express mode and Lambda Web Adapter mode.
5
+ *
6
+ * @param req - Optional Express request object. Required for Web Adapter mode
7
+ * to extract the x-amzn-request-id header.
8
+ * @returns The AWS request ID or undefined if not in Lambda context
9
+ */
10
+ declare function getCurrentInvokeUuid(req?: Request): string | undefined;
2
11
  export default getCurrentInvokeUuid;
@@ -0,0 +1,12 @@
1
+ import type { Request } from "express";
2
+ /**
3
+ * Get the current invoke UUID from Lambda Web Adapter context.
4
+ * This function extracts the request ID from either:
5
+ * 1. The x-amzn-request-id header (set by Lambda Web Adapter)
6
+ * 2. The _X_AMZN_TRACE_ID environment variable (set by Lambda runtime)
7
+ *
8
+ * @param req - Optional Express request object to extract headers from
9
+ * @returns The AWS request ID or undefined if not in Lambda context
10
+ */
11
+ declare function getWebAdapterUuid(req?: Request): string | undefined;
12
+ export default getWebAdapterUuid;
@@ -3,8 +3,8 @@
3
3
  var errors = require('@jaypie/errors');
4
4
  var kit = require('@jaypie/kit');
5
5
  var expressCors = require('cors');
6
- var aws = require('@jaypie/aws');
7
6
  var logger$2 = require('@jaypie/logger');
7
+ var aws = require('@jaypie/aws');
8
8
  var datadog = require('@jaypie/datadog');
9
9
  var serverlessExpress = require('@codegenie/serverless-express');
10
10
 
@@ -94,7 +94,7 @@ const corsHelper = (config = {}) => {
94
94
  };
95
95
  return expressCors(options);
96
96
  };
97
- var cors_helper = (config) => {
97
+ var cors = (config) => {
98
98
  const cors = corsHelper(config);
99
99
  return (req, res, next) => {
100
100
  cors(req, res, (error) => {
@@ -109,11 +109,157 @@ var cors_helper = (config) => {
109
109
  };
110
110
  };
111
111
 
112
+ //
113
+ //
114
+ // Constants
115
+ //
116
+ const DEFAULT_PORT = 8080;
117
+ //
118
+ //
119
+ // Main
120
+ //
121
+ /**
122
+ * Creates and starts an Express server with standard Jaypie middleware.
123
+ *
124
+ * Features:
125
+ * - CORS handling (configurable)
126
+ * - JSON body parsing
127
+ * - Listens on PORT env var (default 8080)
128
+ *
129
+ * Usage:
130
+ * ```ts
131
+ * import express from "express";
132
+ * import { createServer, expressHandler } from "@jaypie/express";
133
+ *
134
+ * const app = express();
135
+ *
136
+ * app.get("/", expressHandler(async (req, res) => {
137
+ * return { message: "Hello World" };
138
+ * }));
139
+ *
140
+ * const { server, port } = await createServer(app);
141
+ * console.log(`Server running on port ${port}`);
142
+ * ```
143
+ *
144
+ * @param app - Express application instance
145
+ * @param options - Server configuration options
146
+ * @returns Promise resolving to server instance and port
147
+ */
148
+ async function createServer(app, options = {}) {
149
+ const { cors: corsConfig, jsonLimit = "1mb", middleware = [], port: portOption, } = options;
150
+ // Determine port
151
+ const port = typeof portOption === "string"
152
+ ? parseInt(portOption, 10)
153
+ : (portOption ?? parseInt(process.env.PORT || String(DEFAULT_PORT), 10));
154
+ // Apply CORS middleware (unless explicitly disabled)
155
+ if (corsConfig !== false) {
156
+ app.use(cors(corsConfig));
157
+ }
158
+ // Apply JSON body parser
159
+ // Note: We use dynamic import to avoid requiring express as a direct dependency
160
+ const express = await import('express');
161
+ app.use(express.json({ limit: jsonLimit }));
162
+ // Apply additional middleware
163
+ for (const mw of middleware) {
164
+ app.use(mw);
165
+ }
166
+ // Start server
167
+ return new Promise((resolve, reject) => {
168
+ try {
169
+ const server = app.listen(port, () => {
170
+ // Get the actual port (important when port 0 is passed to get an ephemeral port)
171
+ const address = server.address();
172
+ const actualPort = address?.port ?? port;
173
+ logger$2.log.info(`Server listening on port ${actualPort}`);
174
+ resolve({ port: actualPort, server });
175
+ });
176
+ server.on("error", (error) => {
177
+ logger$2.log.error("Server error", { error });
178
+ reject(error);
179
+ });
180
+ }
181
+ catch (error) {
182
+ reject(error);
183
+ }
184
+ });
185
+ }
186
+
187
+ //
188
+ //
189
+ // Constants
190
+ //
191
+ const HEADER_AMZN_REQUEST_ID$1 = "x-amzn-request-id";
192
+ const ENV_AMZN_TRACE_ID = "_X_AMZN_TRACE_ID";
112
193
  //
113
194
  //
114
195
  // Helper Functions
115
196
  //
116
- // Adapter for the "@codegenie/serverless-express" uuid
197
+ /**
198
+ * Extract request ID from X-Ray trace ID environment variable
199
+ * Format: Root=1-5e6b4a90-example;Parent=example;Sampled=1
200
+ * We extract the trace ID from the Root segment
201
+ */
202
+ function parseTraceId(traceId) {
203
+ if (!traceId)
204
+ return undefined;
205
+ // Extract the Root segment (format: Root=1-{timestamp}-{uuid})
206
+ const rootMatch = traceId.match(/Root=([^;]+)/);
207
+ if (rootMatch && rootMatch[1]) {
208
+ return rootMatch[1];
209
+ }
210
+ return undefined;
211
+ }
212
+ //
213
+ //
214
+ // Main
215
+ //
216
+ /**
217
+ * Get the current invoke UUID from Lambda Web Adapter context.
218
+ * This function extracts the request ID from either:
219
+ * 1. The x-amzn-request-id header (set by Lambda Web Adapter)
220
+ * 2. The _X_AMZN_TRACE_ID environment variable (set by Lambda runtime)
221
+ *
222
+ * @param req - Optional Express request object to extract headers from
223
+ * @returns The AWS request ID or undefined if not in Lambda context
224
+ */
225
+ function getWebAdapterUuid(req) {
226
+ // First, try to get from request headers
227
+ if (req && req.headers) {
228
+ const headerValue = req.headers[HEADER_AMZN_REQUEST_ID$1];
229
+ if (headerValue) {
230
+ return Array.isArray(headerValue) ? headerValue[0] : headerValue;
231
+ }
232
+ }
233
+ // Fall back to environment variable (X-Ray trace ID)
234
+ const traceId = process.env[ENV_AMZN_TRACE_ID];
235
+ if (traceId) {
236
+ return parseTraceId(traceId);
237
+ }
238
+ return undefined;
239
+ }
240
+
241
+ //
242
+ //
243
+ // Constants
244
+ //
245
+ const HEADER_AMZN_REQUEST_ID = "x-amzn-request-id";
246
+ //
247
+ //
248
+ // Helper Functions
249
+ //
250
+ /**
251
+ * Detect if we're running in Lambda Web Adapter mode.
252
+ * Web Adapter sets the x-amzn-request-id header on requests.
253
+ */
254
+ function isWebAdapterMode(req) {
255
+ if (req && req.headers && req.headers[HEADER_AMZN_REQUEST_ID]) {
256
+ return true;
257
+ }
258
+ return false;
259
+ }
260
+ /**
261
+ * Adapter for the "@codegenie/serverless-express" uuid
262
+ */
117
263
  function getServerlessExpressUuid() {
118
264
  const currentInvoke = serverlessExpress.getCurrentInvoke();
119
265
  if (currentInvoke &&
@@ -127,7 +273,27 @@ function getServerlessExpressUuid() {
127
273
  //
128
274
  // Main
129
275
  //
130
- const getCurrentInvokeUuid = () => getServerlessExpressUuid();
276
+ /**
277
+ * Get the current invoke UUID from Lambda context.
278
+ * Works in both serverless-express mode and Lambda Web Adapter mode.
279
+ *
280
+ * @param req - Optional Express request object. Required for Web Adapter mode
281
+ * to extract the x-amzn-request-id header.
282
+ * @returns The AWS request ID or undefined if not in Lambda context
283
+ */
284
+ function getCurrentInvokeUuid(req) {
285
+ // If request is provided and has Web Adapter header, use Web Adapter mode
286
+ if (isWebAdapterMode(req)) {
287
+ return getWebAdapterUuid(req);
288
+ }
289
+ // Try serverless-express mode first
290
+ const serverlessExpressUuid = getServerlessExpressUuid();
291
+ if (serverlessExpressUuid) {
292
+ return serverlessExpressUuid;
293
+ }
294
+ // If no request but we might be in Web Adapter mode, try env var fallback
295
+ return getWebAdapterUuid();
296
+ }
131
297
 
132
298
  //
133
299
  //
@@ -289,7 +455,7 @@ function expressHandler(handlerOrOptions, optionsOrHandler) {
289
455
  lib: kit.JAYPIE.LIB.EXPRESS,
290
456
  });
291
457
  // Update the public logger with the request ID
292
- const invokeUuid = getCurrentInvokeUuid();
458
+ const invokeUuid = getCurrentInvokeUuid(req);
293
459
  if (invokeUuid) {
294
460
  logger$1.tag({ invoke: invokeUuid });
295
461
  logger$1.tag({ shortInvoke: invokeUuid.slice(0, 8) });
@@ -611,7 +777,7 @@ function expressStreamHandler(handlerOrOptions, optionsOrHandler) {
611
777
  lib: kit.JAYPIE.LIB.EXPRESS,
612
778
  });
613
779
  // Update the public logger with the request ID
614
- const invokeUuid = getCurrentInvokeUuid();
780
+ const invokeUuid = getCurrentInvokeUuid(req);
615
781
  if (invokeUuid) {
616
782
  logger.tag({ invoke: invokeUuid });
617
783
  logger.tag({ shortInvoke: invokeUuid.slice(0, 8) });
@@ -868,12 +1034,14 @@ const notImplementedRoute = routes.notImplementedRoute;
868
1034
 
869
1035
  exports.EXPRESS = EXPRESS;
870
1036
  exports.badRequestRoute = badRequestRoute;
871
- exports.cors = cors_helper;
1037
+ exports.cors = cors;
1038
+ exports.createServer = createServer;
872
1039
  exports.echoRoute = echoRoute;
873
1040
  exports.expressHandler = expressHandler;
874
1041
  exports.expressHttpCodeHandler = httpHandler;
875
1042
  exports.expressStreamHandler = expressStreamHandler;
876
1043
  exports.forbiddenRoute = forbiddenRoute;
1044
+ exports.getCurrentInvokeUuid = getCurrentInvokeUuid;
877
1045
  exports.goneRoute = goneRoute;
878
1046
  exports.methodNotAllowedRoute = methodNotAllowedRoute;
879
1047
  exports.noContentRoute = noContentRoute;