@aegislog/express 0.2.3 → 0.2.4

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/index.cjs CHANGED
@@ -30,13 +30,21 @@ function aegisExpressMiddleware(options = {}) {
30
30
  const logRequests = options.logRequests ?? true;
31
31
  const activeLogger = options.logger ?? import_aegislog.logger;
32
32
  return async (req, res, next) => {
33
- const requestId = req.headers["x-request-id"] || `req_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 9)}`;
34
- const traceHeader = req.headers["traceparent"] || req.headers["x-trace-id"];
33
+ const requestIdHeader = req.headers["x-request-id"];
34
+ const requestId = (Array.isArray(requestIdHeader) ? requestIdHeader[0] : requestIdHeader) ?? (0, import_aegislog.generateId)();
35
+ const rawTraceHeader = req.headers["traceparent"] || req.headers["x-trace-id"];
36
+ const traceHeader = Array.isArray(rawTraceHeader) ? rawTraceHeader[0] : rawTraceHeader;
35
37
  const traceId = traceHeader ? traceHeader.split("-")[1] || traceHeader : void 0;
36
38
  const ip = req.headers["x-forwarded-for"]?.split(",")[0]?.trim() || req.headers["x-real-ip"] || req.socket.remoteAddress;
37
39
  const userAgent = req.headers["user-agent"];
38
- const actor = options.getActor ? await options.getActor(req) : void 0;
39
- const tenant = options.getTenant ? await options.getTenant(req) : void 0;
40
+ let actor;
41
+ let tenant;
42
+ try {
43
+ [actor, tenant] = await Promise.all([options.getActor?.(req), options.getTenant?.(req)]);
44
+ } catch (error) {
45
+ next(error instanceof Error ? error : new Error(String(error)));
46
+ return;
47
+ }
40
48
  (0, import_aegislog.runWithContext)(
41
49
  {
42
50
  requestId,
@@ -50,7 +58,10 @@ function aegisExpressMiddleware(options = {}) {
50
58
  if (logRequests) {
51
59
  activeLogger.debug(`--> ${req.method} ${req.originalUrl || req.url}`);
52
60
  }
61
+ let finished = false;
53
62
  res.on("finish", () => {
63
+ finished = true;
64
+ activeLogger.completeRequest(res.statusCode, requestId);
54
65
  if (!logRequests) return;
55
66
  const duration = Number((performance.now() - start).toFixed(2));
56
67
  const status = res.statusCode;
@@ -64,6 +75,14 @@ function aegisExpressMiddleware(options = {}) {
64
75
  activeLogger.info(msg, { status, durationMs: duration });
65
76
  }
66
77
  });
78
+ res.on("close", () => {
79
+ if (finished) return;
80
+ activeLogger.completeRequest(500, requestId);
81
+ if (!logRequests) return;
82
+ activeLogger.error(`<-- ${req.method} ${req.originalUrl || req.url} connection closed`, {
83
+ status: res.statusCode
84
+ });
85
+ });
67
86
  next();
68
87
  }
69
88
  );
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/middleware.ts"],"sourcesContent":["export * from \"./middleware.js\";\n","import type { NextFunction, Request, Response } from \"express\";\nimport {\n type ActorContext,\n type AegisLogger,\n type TenantContext,\n logger,\n runWithContext,\n} from \"aegislog\";\n\nexport interface ExpressAegisOptions {\n logger?: AegisLogger;\n getActor?: (req: Request) => ActorContext | undefined | Promise<ActorContext | undefined>;\n getTenant?: (req: Request) => TenantContext | undefined | Promise<TenantContext | undefined>;\n logRequests?: boolean;\n}\n\nexport function aegisExpressMiddleware(\n options: ExpressAegisOptions = {},\n): (req: Request, res: Response, next: NextFunction) => Promise<void> {\n const logRequests = options.logRequests ?? true;\n const activeLogger = options.logger ?? logger;\n\n return async (req: Request, res: Response, next: NextFunction): Promise<void> => {\n const requestId =\n (req.headers[\"x-request-id\"] as string) ||\n `req_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 9)}`;\n\n const traceHeader = (req.headers[\"traceparent\"] || req.headers[\"x-trace-id\"]) as string;\n const traceId = traceHeader ? traceHeader.split(\"-\")[1] || traceHeader : undefined;\n\n const ip =\n (req.headers[\"x-forwarded-for\"] as string)?.split(\",\")[0]?.trim() ||\n (req.headers[\"x-real-ip\"] as string) ||\n req.socket.remoteAddress;\n\n const userAgent = req.headers[\"user-agent\"] as string;\n\n const actor = options.getActor ? await options.getActor(req) : undefined;\n const tenant = options.getTenant ? await options.getTenant(req) : undefined;\n\n runWithContext(\n {\n requestId,\n traceId,\n actor,\n tenant,\n session: { id: requestId, ip, userAgent },\n },\n () => {\n const start = performance.now();\n\n if (logRequests) {\n activeLogger.debug(`--> ${req.method} ${req.originalUrl || req.url}`);\n }\n\n res.on(\"finish\", () => {\n if (!logRequests) return;\n const duration = Number((performance.now() - start).toFixed(2));\n const status = res.statusCode;\n const level = status >= 500 ? \"error\" : status >= 400 ? \"warn\" : \"info\";\n const msg = `<-- ${req.method} ${req.originalUrl || req.url} ${status} in ${duration}ms`;\n\n if (level === \"error\") {\n activeLogger.error(msg, { status, durationMs: duration });\n } else if (level === \"warn\") {\n activeLogger.warn(msg, { status, durationMs: duration });\n } else {\n activeLogger.info(msg, { status, durationMs: duration });\n }\n });\n\n next();\n },\n );\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCA,sBAMO;AASA,SAAS,uBACd,UAA+B,CAAC,GACoC;AACpE,QAAM,cAAc,QAAQ,eAAe;AAC3C,QAAM,eAAe,QAAQ,UAAU;AAEvC,SAAO,OAAO,KAAc,KAAe,SAAsC;AAC/E,UAAM,YACH,IAAI,QAAQ,cAAc,KAC3B,OAAO,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAE1E,UAAM,cAAe,IAAI,QAAQ,aAAa,KAAK,IAAI,QAAQ,YAAY;AAC3E,UAAM,UAAU,cAAc,YAAY,MAAM,GAAG,EAAE,CAAC,KAAK,cAAc;AAEzE,UAAM,KACH,IAAI,QAAQ,iBAAiB,GAAc,MAAM,GAAG,EAAE,CAAC,GAAG,KAAK,KAC/D,IAAI,QAAQ,WAAW,KACxB,IAAI,OAAO;AAEb,UAAM,YAAY,IAAI,QAAQ,YAAY;AAE1C,UAAM,QAAQ,QAAQ,WAAW,MAAM,QAAQ,SAAS,GAAG,IAAI;AAC/D,UAAM,SAAS,QAAQ,YAAY,MAAM,QAAQ,UAAU,GAAG,IAAI;AAElE;AAAA,MACE;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,SAAS,EAAE,IAAI,WAAW,IAAI,UAAU;AAAA,MAC1C;AAAA,MACA,MAAM;AACJ,cAAM,QAAQ,YAAY,IAAI;AAE9B,YAAI,aAAa;AACf,uBAAa,MAAM,OAAO,IAAI,MAAM,IAAI,IAAI,eAAe,IAAI,GAAG,EAAE;AAAA,QACtE;AAEA,YAAI,GAAG,UAAU,MAAM;AACrB,cAAI,CAAC,YAAa;AAClB,gBAAM,WAAW,QAAQ,YAAY,IAAI,IAAI,OAAO,QAAQ,CAAC,CAAC;AAC9D,gBAAM,SAAS,IAAI;AACnB,gBAAM,QAAQ,UAAU,MAAM,UAAU,UAAU,MAAM,SAAS;AACjE,gBAAM,MAAM,OAAO,IAAI,MAAM,IAAI,IAAI,eAAe,IAAI,GAAG,IAAI,MAAM,OAAO,QAAQ;AAEpF,cAAI,UAAU,SAAS;AACrB,yBAAa,MAAM,KAAK,EAAE,QAAQ,YAAY,SAAS,CAAC;AAAA,UAC1D,WAAW,UAAU,QAAQ;AAC3B,yBAAa,KAAK,KAAK,EAAE,QAAQ,YAAY,SAAS,CAAC;AAAA,UACzD,OAAO;AACL,yBAAa,KAAK,KAAK,EAAE,QAAQ,YAAY,SAAS,CAAC;AAAA,UACzD;AAAA,QACF,CAAC;AAED,aAAK;AAAA,MACP;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/middleware.ts"],"sourcesContent":["export * from \"./middleware.js\";\n","import type { NextFunction, Request, Response } from \"express\";\nimport {\n type ActorContext,\n type AegisLogger,\n type TenantContext,\n generateId,\n logger,\n runWithContext,\n} from \"aegislog\";\n\nexport interface ExpressAegisOptions {\n logger?: AegisLogger;\n getActor?: (req: Request) => ActorContext | undefined | Promise<ActorContext | undefined>;\n getTenant?: (req: Request) => TenantContext | undefined | Promise<TenantContext | undefined>;\n logRequests?: boolean;\n}\n\nexport function aegisExpressMiddleware(\n options: ExpressAegisOptions = {},\n): (req: Request, res: Response, next: NextFunction) => Promise<void> {\n const logRequests = options.logRequests ?? true;\n const activeLogger = options.logger ?? logger;\n\n return async (req: Request, res: Response, next: NextFunction): Promise<void> => {\n const requestIdHeader = req.headers[\"x-request-id\"];\n const requestId =\n (Array.isArray(requestIdHeader) ? requestIdHeader[0] : requestIdHeader) ?? generateId();\n\n const rawTraceHeader = req.headers[\"traceparent\"] || req.headers[\"x-trace-id\"];\n const traceHeader = Array.isArray(rawTraceHeader) ? rawTraceHeader[0] : rawTraceHeader;\n const traceId = traceHeader ? traceHeader.split(\"-\")[1] || traceHeader : undefined;\n\n const ip =\n (req.headers[\"x-forwarded-for\"] as string)?.split(\",\")[0]?.trim() ||\n (req.headers[\"x-real-ip\"] as string) ||\n req.socket.remoteAddress;\n\n const userAgent = req.headers[\"user-agent\"] as string;\n\n let actor: ActorContext | undefined;\n let tenant: TenantContext | undefined;\n try {\n [actor, tenant] = await Promise.all([options.getActor?.(req), options.getTenant?.(req)]);\n } catch (error) {\n next(error instanceof Error ? error : new Error(String(error)));\n return;\n }\n\n runWithContext(\n {\n requestId,\n traceId,\n actor,\n tenant,\n session: { id: requestId, ip, userAgent },\n },\n () => {\n const start = performance.now();\n\n if (logRequests) {\n activeLogger.debug(`--> ${req.method} ${req.originalUrl || req.url}`);\n }\n\n let finished = false;\n res.on(\"finish\", () => {\n finished = true;\n activeLogger.completeRequest(res.statusCode, requestId);\n if (!logRequests) return;\n const duration = Number((performance.now() - start).toFixed(2));\n const status = res.statusCode;\n const level = status >= 500 ? \"error\" : status >= 400 ? \"warn\" : \"info\";\n const msg = `<-- ${req.method} ${req.originalUrl || req.url} ${status} in ${duration}ms`;\n\n if (level === \"error\") {\n activeLogger.error(msg, { status, durationMs: duration });\n } else if (level === \"warn\") {\n activeLogger.warn(msg, { status, durationMs: duration });\n } else {\n activeLogger.info(msg, { status, durationMs: duration });\n }\n });\n res.on(\"close\", () => {\n if (finished) return;\n activeLogger.completeRequest(500, requestId);\n if (!logRequests) return;\n activeLogger.error(`<-- ${req.method} ${req.originalUrl || req.url} connection closed`, {\n status: res.statusCode,\n });\n });\n\n next();\n },\n );\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCA,sBAOO;AASA,SAAS,uBACd,UAA+B,CAAC,GACoC;AACpE,QAAM,cAAc,QAAQ,eAAe;AAC3C,QAAM,eAAe,QAAQ,UAAU;AAEvC,SAAO,OAAO,KAAc,KAAe,SAAsC;AAC/E,UAAM,kBAAkB,IAAI,QAAQ,cAAc;AAClD,UAAM,aACH,MAAM,QAAQ,eAAe,IAAI,gBAAgB,CAAC,IAAI,wBAAoB,4BAAW;AAExF,UAAM,iBAAiB,IAAI,QAAQ,aAAa,KAAK,IAAI,QAAQ,YAAY;AAC7E,UAAM,cAAc,MAAM,QAAQ,cAAc,IAAI,eAAe,CAAC,IAAI;AACxE,UAAM,UAAU,cAAc,YAAY,MAAM,GAAG,EAAE,CAAC,KAAK,cAAc;AAEzE,UAAM,KACH,IAAI,QAAQ,iBAAiB,GAAc,MAAM,GAAG,EAAE,CAAC,GAAG,KAAK,KAC/D,IAAI,QAAQ,WAAW,KACxB,IAAI,OAAO;AAEb,UAAM,YAAY,IAAI,QAAQ,YAAY;AAE1C,QAAI;AACJ,QAAI;AACJ,QAAI;AACF,OAAC,OAAO,MAAM,IAAI,MAAM,QAAQ,IAAI,CAAC,QAAQ,WAAW,GAAG,GAAG,QAAQ,YAAY,GAAG,CAAC,CAAC;AAAA,IACzF,SAAS,OAAO;AACd,WAAK,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAC9D;AAAA,IACF;AAEA;AAAA,MACE;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,SAAS,EAAE,IAAI,WAAW,IAAI,UAAU;AAAA,MAC1C;AAAA,MACA,MAAM;AACJ,cAAM,QAAQ,YAAY,IAAI;AAE9B,YAAI,aAAa;AACf,uBAAa,MAAM,OAAO,IAAI,MAAM,IAAI,IAAI,eAAe,IAAI,GAAG,EAAE;AAAA,QACtE;AAEA,YAAI,WAAW;AACf,YAAI,GAAG,UAAU,MAAM;AACrB,qBAAW;AACX,uBAAa,gBAAgB,IAAI,YAAY,SAAS;AACtD,cAAI,CAAC,YAAa;AAClB,gBAAM,WAAW,QAAQ,YAAY,IAAI,IAAI,OAAO,QAAQ,CAAC,CAAC;AAC9D,gBAAM,SAAS,IAAI;AACnB,gBAAM,QAAQ,UAAU,MAAM,UAAU,UAAU,MAAM,SAAS;AACjE,gBAAM,MAAM,OAAO,IAAI,MAAM,IAAI,IAAI,eAAe,IAAI,GAAG,IAAI,MAAM,OAAO,QAAQ;AAEpF,cAAI,UAAU,SAAS;AACrB,yBAAa,MAAM,KAAK,EAAE,QAAQ,YAAY,SAAS,CAAC;AAAA,UAC1D,WAAW,UAAU,QAAQ;AAC3B,yBAAa,KAAK,KAAK,EAAE,QAAQ,YAAY,SAAS,CAAC;AAAA,UACzD,OAAO;AACL,yBAAa,KAAK,KAAK,EAAE,QAAQ,YAAY,SAAS,CAAC;AAAA,UACzD;AAAA,QACF,CAAC;AACD,YAAI,GAAG,SAAS,MAAM;AACpB,cAAI,SAAU;AACd,uBAAa,gBAAgB,KAAK,SAAS;AAC3C,cAAI,CAAC,YAAa;AAClB,uBAAa,MAAM,OAAO,IAAI,MAAM,IAAI,IAAI,eAAe,IAAI,GAAG,sBAAsB;AAAA,YACtF,QAAQ,IAAI;AAAA,UACd,CAAC;AAAA,QACH,CAAC;AAED,aAAK;AAAA,MACP;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  // src/middleware.ts
2
2
  import {
3
+ generateId,
3
4
  logger,
4
5
  runWithContext
5
6
  } from "aegislog";
@@ -7,13 +8,21 @@ function aegisExpressMiddleware(options = {}) {
7
8
  const logRequests = options.logRequests ?? true;
8
9
  const activeLogger = options.logger ?? logger;
9
10
  return async (req, res, next) => {
10
- const requestId = req.headers["x-request-id"] || `req_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 9)}`;
11
- const traceHeader = req.headers["traceparent"] || req.headers["x-trace-id"];
11
+ const requestIdHeader = req.headers["x-request-id"];
12
+ const requestId = (Array.isArray(requestIdHeader) ? requestIdHeader[0] : requestIdHeader) ?? generateId();
13
+ const rawTraceHeader = req.headers["traceparent"] || req.headers["x-trace-id"];
14
+ const traceHeader = Array.isArray(rawTraceHeader) ? rawTraceHeader[0] : rawTraceHeader;
12
15
  const traceId = traceHeader ? traceHeader.split("-")[1] || traceHeader : void 0;
13
16
  const ip = req.headers["x-forwarded-for"]?.split(",")[0]?.trim() || req.headers["x-real-ip"] || req.socket.remoteAddress;
14
17
  const userAgent = req.headers["user-agent"];
15
- const actor = options.getActor ? await options.getActor(req) : void 0;
16
- const tenant = options.getTenant ? await options.getTenant(req) : void 0;
18
+ let actor;
19
+ let tenant;
20
+ try {
21
+ [actor, tenant] = await Promise.all([options.getActor?.(req), options.getTenant?.(req)]);
22
+ } catch (error) {
23
+ next(error instanceof Error ? error : new Error(String(error)));
24
+ return;
25
+ }
17
26
  runWithContext(
18
27
  {
19
28
  requestId,
@@ -27,7 +36,10 @@ function aegisExpressMiddleware(options = {}) {
27
36
  if (logRequests) {
28
37
  activeLogger.debug(`--> ${req.method} ${req.originalUrl || req.url}`);
29
38
  }
39
+ let finished = false;
30
40
  res.on("finish", () => {
41
+ finished = true;
42
+ activeLogger.completeRequest(res.statusCode, requestId);
31
43
  if (!logRequests) return;
32
44
  const duration = Number((performance.now() - start).toFixed(2));
33
45
  const status = res.statusCode;
@@ -41,6 +53,14 @@ function aegisExpressMiddleware(options = {}) {
41
53
  activeLogger.info(msg, { status, durationMs: duration });
42
54
  }
43
55
  });
56
+ res.on("close", () => {
57
+ if (finished) return;
58
+ activeLogger.completeRequest(500, requestId);
59
+ if (!logRequests) return;
60
+ activeLogger.error(`<-- ${req.method} ${req.originalUrl || req.url} connection closed`, {
61
+ status: res.statusCode
62
+ });
63
+ });
44
64
  next();
45
65
  }
46
66
  );
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/middleware.ts"],"sourcesContent":["import type { NextFunction, Request, Response } from \"express\";\nimport {\n type ActorContext,\n type AegisLogger,\n type TenantContext,\n logger,\n runWithContext,\n} from \"aegislog\";\n\nexport interface ExpressAegisOptions {\n logger?: AegisLogger;\n getActor?: (req: Request) => ActorContext | undefined | Promise<ActorContext | undefined>;\n getTenant?: (req: Request) => TenantContext | undefined | Promise<TenantContext | undefined>;\n logRequests?: boolean;\n}\n\nexport function aegisExpressMiddleware(\n options: ExpressAegisOptions = {},\n): (req: Request, res: Response, next: NextFunction) => Promise<void> {\n const logRequests = options.logRequests ?? true;\n const activeLogger = options.logger ?? logger;\n\n return async (req: Request, res: Response, next: NextFunction): Promise<void> => {\n const requestId =\n (req.headers[\"x-request-id\"] as string) ||\n `req_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 9)}`;\n\n const traceHeader = (req.headers[\"traceparent\"] || req.headers[\"x-trace-id\"]) as string;\n const traceId = traceHeader ? traceHeader.split(\"-\")[1] || traceHeader : undefined;\n\n const ip =\n (req.headers[\"x-forwarded-for\"] as string)?.split(\",\")[0]?.trim() ||\n (req.headers[\"x-real-ip\"] as string) ||\n req.socket.remoteAddress;\n\n const userAgent = req.headers[\"user-agent\"] as string;\n\n const actor = options.getActor ? await options.getActor(req) : undefined;\n const tenant = options.getTenant ? await options.getTenant(req) : undefined;\n\n runWithContext(\n {\n requestId,\n traceId,\n actor,\n tenant,\n session: { id: requestId, ip, userAgent },\n },\n () => {\n const start = performance.now();\n\n if (logRequests) {\n activeLogger.debug(`--> ${req.method} ${req.originalUrl || req.url}`);\n }\n\n res.on(\"finish\", () => {\n if (!logRequests) return;\n const duration = Number((performance.now() - start).toFixed(2));\n const status = res.statusCode;\n const level = status >= 500 ? \"error\" : status >= 400 ? \"warn\" : \"info\";\n const msg = `<-- ${req.method} ${req.originalUrl || req.url} ${status} in ${duration}ms`;\n\n if (level === \"error\") {\n activeLogger.error(msg, { status, durationMs: duration });\n } else if (level === \"warn\") {\n activeLogger.warn(msg, { status, durationMs: duration });\n } else {\n activeLogger.info(msg, { status, durationMs: duration });\n }\n });\n\n next();\n },\n );\n };\n}\n"],"mappings":";AACA;AAAA,EAIE;AAAA,EACA;AAAA,OACK;AASA,SAAS,uBACd,UAA+B,CAAC,GACoC;AACpE,QAAM,cAAc,QAAQ,eAAe;AAC3C,QAAM,eAAe,QAAQ,UAAU;AAEvC,SAAO,OAAO,KAAc,KAAe,SAAsC;AAC/E,UAAM,YACH,IAAI,QAAQ,cAAc,KAC3B,OAAO,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAE1E,UAAM,cAAe,IAAI,QAAQ,aAAa,KAAK,IAAI,QAAQ,YAAY;AAC3E,UAAM,UAAU,cAAc,YAAY,MAAM,GAAG,EAAE,CAAC,KAAK,cAAc;AAEzE,UAAM,KACH,IAAI,QAAQ,iBAAiB,GAAc,MAAM,GAAG,EAAE,CAAC,GAAG,KAAK,KAC/D,IAAI,QAAQ,WAAW,KACxB,IAAI,OAAO;AAEb,UAAM,YAAY,IAAI,QAAQ,YAAY;AAE1C,UAAM,QAAQ,QAAQ,WAAW,MAAM,QAAQ,SAAS,GAAG,IAAI;AAC/D,UAAM,SAAS,QAAQ,YAAY,MAAM,QAAQ,UAAU,GAAG,IAAI;AAElE;AAAA,MACE;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,SAAS,EAAE,IAAI,WAAW,IAAI,UAAU;AAAA,MAC1C;AAAA,MACA,MAAM;AACJ,cAAM,QAAQ,YAAY,IAAI;AAE9B,YAAI,aAAa;AACf,uBAAa,MAAM,OAAO,IAAI,MAAM,IAAI,IAAI,eAAe,IAAI,GAAG,EAAE;AAAA,QACtE;AAEA,YAAI,GAAG,UAAU,MAAM;AACrB,cAAI,CAAC,YAAa;AAClB,gBAAM,WAAW,QAAQ,YAAY,IAAI,IAAI,OAAO,QAAQ,CAAC,CAAC;AAC9D,gBAAM,SAAS,IAAI;AACnB,gBAAM,QAAQ,UAAU,MAAM,UAAU,UAAU,MAAM,SAAS;AACjE,gBAAM,MAAM,OAAO,IAAI,MAAM,IAAI,IAAI,eAAe,IAAI,GAAG,IAAI,MAAM,OAAO,QAAQ;AAEpF,cAAI,UAAU,SAAS;AACrB,yBAAa,MAAM,KAAK,EAAE,QAAQ,YAAY,SAAS,CAAC;AAAA,UAC1D,WAAW,UAAU,QAAQ;AAC3B,yBAAa,KAAK,KAAK,EAAE,QAAQ,YAAY,SAAS,CAAC;AAAA,UACzD,OAAO;AACL,yBAAa,KAAK,KAAK,EAAE,QAAQ,YAAY,SAAS,CAAC;AAAA,UACzD;AAAA,QACF,CAAC;AAED,aAAK;AAAA,MACP;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/middleware.ts"],"sourcesContent":["import type { NextFunction, Request, Response } from \"express\";\nimport {\n type ActorContext,\n type AegisLogger,\n type TenantContext,\n generateId,\n logger,\n runWithContext,\n} from \"aegislog\";\n\nexport interface ExpressAegisOptions {\n logger?: AegisLogger;\n getActor?: (req: Request) => ActorContext | undefined | Promise<ActorContext | undefined>;\n getTenant?: (req: Request) => TenantContext | undefined | Promise<TenantContext | undefined>;\n logRequests?: boolean;\n}\n\nexport function aegisExpressMiddleware(\n options: ExpressAegisOptions = {},\n): (req: Request, res: Response, next: NextFunction) => Promise<void> {\n const logRequests = options.logRequests ?? true;\n const activeLogger = options.logger ?? logger;\n\n return async (req: Request, res: Response, next: NextFunction): Promise<void> => {\n const requestIdHeader = req.headers[\"x-request-id\"];\n const requestId =\n (Array.isArray(requestIdHeader) ? requestIdHeader[0] : requestIdHeader) ?? generateId();\n\n const rawTraceHeader = req.headers[\"traceparent\"] || req.headers[\"x-trace-id\"];\n const traceHeader = Array.isArray(rawTraceHeader) ? rawTraceHeader[0] : rawTraceHeader;\n const traceId = traceHeader ? traceHeader.split(\"-\")[1] || traceHeader : undefined;\n\n const ip =\n (req.headers[\"x-forwarded-for\"] as string)?.split(\",\")[0]?.trim() ||\n (req.headers[\"x-real-ip\"] as string) ||\n req.socket.remoteAddress;\n\n const userAgent = req.headers[\"user-agent\"] as string;\n\n let actor: ActorContext | undefined;\n let tenant: TenantContext | undefined;\n try {\n [actor, tenant] = await Promise.all([options.getActor?.(req), options.getTenant?.(req)]);\n } catch (error) {\n next(error instanceof Error ? error : new Error(String(error)));\n return;\n }\n\n runWithContext(\n {\n requestId,\n traceId,\n actor,\n tenant,\n session: { id: requestId, ip, userAgent },\n },\n () => {\n const start = performance.now();\n\n if (logRequests) {\n activeLogger.debug(`--> ${req.method} ${req.originalUrl || req.url}`);\n }\n\n let finished = false;\n res.on(\"finish\", () => {\n finished = true;\n activeLogger.completeRequest(res.statusCode, requestId);\n if (!logRequests) return;\n const duration = Number((performance.now() - start).toFixed(2));\n const status = res.statusCode;\n const level = status >= 500 ? \"error\" : status >= 400 ? \"warn\" : \"info\";\n const msg = `<-- ${req.method} ${req.originalUrl || req.url} ${status} in ${duration}ms`;\n\n if (level === \"error\") {\n activeLogger.error(msg, { status, durationMs: duration });\n } else if (level === \"warn\") {\n activeLogger.warn(msg, { status, durationMs: duration });\n } else {\n activeLogger.info(msg, { status, durationMs: duration });\n }\n });\n res.on(\"close\", () => {\n if (finished) return;\n activeLogger.completeRequest(500, requestId);\n if (!logRequests) return;\n activeLogger.error(`<-- ${req.method} ${req.originalUrl || req.url} connection closed`, {\n status: res.statusCode,\n });\n });\n\n next();\n },\n );\n };\n}\n"],"mappings":";AACA;AAAA,EAIE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AASA,SAAS,uBACd,UAA+B,CAAC,GACoC;AACpE,QAAM,cAAc,QAAQ,eAAe;AAC3C,QAAM,eAAe,QAAQ,UAAU;AAEvC,SAAO,OAAO,KAAc,KAAe,SAAsC;AAC/E,UAAM,kBAAkB,IAAI,QAAQ,cAAc;AAClD,UAAM,aACH,MAAM,QAAQ,eAAe,IAAI,gBAAgB,CAAC,IAAI,oBAAoB,WAAW;AAExF,UAAM,iBAAiB,IAAI,QAAQ,aAAa,KAAK,IAAI,QAAQ,YAAY;AAC7E,UAAM,cAAc,MAAM,QAAQ,cAAc,IAAI,eAAe,CAAC,IAAI;AACxE,UAAM,UAAU,cAAc,YAAY,MAAM,GAAG,EAAE,CAAC,KAAK,cAAc;AAEzE,UAAM,KACH,IAAI,QAAQ,iBAAiB,GAAc,MAAM,GAAG,EAAE,CAAC,GAAG,KAAK,KAC/D,IAAI,QAAQ,WAAW,KACxB,IAAI,OAAO;AAEb,UAAM,YAAY,IAAI,QAAQ,YAAY;AAE1C,QAAI;AACJ,QAAI;AACJ,QAAI;AACF,OAAC,OAAO,MAAM,IAAI,MAAM,QAAQ,IAAI,CAAC,QAAQ,WAAW,GAAG,GAAG,QAAQ,YAAY,GAAG,CAAC,CAAC;AAAA,IACzF,SAAS,OAAO;AACd,WAAK,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAC9D;AAAA,IACF;AAEA;AAAA,MACE;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,SAAS,EAAE,IAAI,WAAW,IAAI,UAAU;AAAA,MAC1C;AAAA,MACA,MAAM;AACJ,cAAM,QAAQ,YAAY,IAAI;AAE9B,YAAI,aAAa;AACf,uBAAa,MAAM,OAAO,IAAI,MAAM,IAAI,IAAI,eAAe,IAAI,GAAG,EAAE;AAAA,QACtE;AAEA,YAAI,WAAW;AACf,YAAI,GAAG,UAAU,MAAM;AACrB,qBAAW;AACX,uBAAa,gBAAgB,IAAI,YAAY,SAAS;AACtD,cAAI,CAAC,YAAa;AAClB,gBAAM,WAAW,QAAQ,YAAY,IAAI,IAAI,OAAO,QAAQ,CAAC,CAAC;AAC9D,gBAAM,SAAS,IAAI;AACnB,gBAAM,QAAQ,UAAU,MAAM,UAAU,UAAU,MAAM,SAAS;AACjE,gBAAM,MAAM,OAAO,IAAI,MAAM,IAAI,IAAI,eAAe,IAAI,GAAG,IAAI,MAAM,OAAO,QAAQ;AAEpF,cAAI,UAAU,SAAS;AACrB,yBAAa,MAAM,KAAK,EAAE,QAAQ,YAAY,SAAS,CAAC;AAAA,UAC1D,WAAW,UAAU,QAAQ;AAC3B,yBAAa,KAAK,KAAK,EAAE,QAAQ,YAAY,SAAS,CAAC;AAAA,UACzD,OAAO;AACL,yBAAa,KAAK,KAAK,EAAE,QAAQ,YAAY,SAAS,CAAC;AAAA,UACzD;AAAA,QACF,CAAC;AACD,YAAI,GAAG,SAAS,MAAM;AACpB,cAAI,SAAU;AACd,uBAAa,gBAAgB,KAAK,SAAS;AAC3C,cAAI,CAAC,YAAa;AAClB,uBAAa,MAAM,OAAO,IAAI,MAAM,IAAI,IAAI,eAAe,IAAI,GAAG,sBAAsB;AAAA,YACtF,QAAQ,IAAI;AAAA,UACd,CAAC;AAAA,QACH,CAAC;AAED,aAAK;AAAA,MACP;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aegislog/express",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "Express middleware adapter for AegisLog.",
5
5
  "homepage": "https://github.com/syedmuzamilm/aegislog#readme",
6
6
  "license": "MIT",
@@ -29,7 +29,7 @@
29
29
  "access": "public"
30
30
  },
31
31
  "dependencies": {
32
- "aegislog": "0.2.3"
32
+ "aegislog": "0.2.4"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/express": "^5.0.0",