@batkit/express-middleware 0.1.1 → 0.1.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.
package/README.md CHANGED
@@ -141,7 +141,6 @@ class CustomErrorFormatter implements ErrorFormatter {
141
141
  app.use(
142
142
  errorHandler({
143
143
  formatters: [new CustomErrorFormatter()],
144
- includeStack: true, // Include stack traces
145
144
  logErrors: true,
146
145
  }),
147
146
  );
@@ -179,7 +178,6 @@ Creates error handling middleware that converts errors to RFC 9457 format.
179
178
  ```typescript
180
179
  interface ErrorHandlerOptions {
181
180
  formatters?: ErrorFormatter[]; // Custom error formatters
182
- includeStack?: boolean; // Include stack traces (default: only in dev)
183
181
  logErrors?: boolean; // Whether to log errors (default: true)
184
182
  onError?: (error: unknown, req: Request) => void; // Custom error logger
185
183
  }
@@ -310,11 +308,7 @@ app.post(
310
308
  );
311
309
 
312
310
  // Error handler (MUST be last)
313
- app.use(
314
- errorHandler({
315
- includeStack: true,
316
- }),
317
- );
311
+ app.use(errorHandler());
318
312
 
319
313
  const PORT = process.env.PORT || 3000;
320
314
  app.listen(PORT, () => {
@@ -14,7 +14,6 @@ export declare class DefaultErrorFormatter implements ErrorFormatter {
14
14
  }
15
15
  export interface ErrorHandlerOptions {
16
16
  formatters?: ErrorFormatter[];
17
- includeStack?: boolean;
18
17
  logErrors?: boolean;
19
18
  onError?: (error: unknown, req: Request) => void;
20
19
  }
@@ -1 +1 @@
1
- {"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../src/error-handler.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,sBAAsB,EAG5B,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAM/D,MAAM,WAAW,cAAc;IAI7B,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;IAKnC,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,sBAAsB,CAAC;CAChD;AAKD,qBAAa,qBAAsB,YAAW,cAAc;IAC1D,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO;IASlC,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,sBAAsB;IAmC9C,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,cAAc;CAevB;AAKD,MAAM,WAAW,mBAAmB;IAIlC,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;IAK9B,YAAY,CAAC,EAAE,OAAO,CAAC;IAKvB,SAAS,CAAC,EAAE,OAAO,CAAC;IAKpB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;CAClD;AAwBD,wBAAgB,YAAY,CAC1B,OAAO,GAAE,mBAAwB,GAChC,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAuEzE;AAsBD,wBAAgB,YAAY,CAC1B,EAAE,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,OAAO,CAAC,GACxE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAI3D"}
1
+ {"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../src/error-handler.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,sBAAsB,EAG5B,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAM/D,MAAM,WAAW,cAAc;IAI7B,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;IAKnC,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,sBAAsB,CAAC;CAChD;AAKD,qBAAa,qBAAsB,YAAW,cAAc;IAC1D,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO;IASlC,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,sBAAsB;IAmC9C,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,cAAc;CAevB;AAKD,MAAM,WAAW,mBAAmB;IAIlC,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;IAK9B,SAAS,CAAC,EAAE,OAAO,CAAC;IAKpB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;CAClD;AAwBD,wBAAgB,YAAY,CAC1B,OAAO,GAAE,mBAAwB,GAChC,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAoEzE;AAsBD,wBAAgB,YAAY,CAC1B,EAAE,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,OAAO,CAAC,GACxE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAI3D"}
@@ -67,14 +67,14 @@ export class DefaultErrorFormatter {
67
67
  return createExtendedProblemDetails({
68
68
  type: "error:validation",
69
69
  title: "Validation Error",
70
- status: 400,
70
+ status: 422,
71
71
  detail: "Request validation failed",
72
72
  validationErrors,
73
73
  });
74
74
  }
75
75
  }
76
76
  export function errorHandler(options = {}) {
77
- const { formatters = [new DefaultErrorFormatter()], includeStack = true, logErrors = true, onError, } = options;
77
+ const { formatters = [new DefaultErrorFormatter()], logErrors = true, onError } = options;
78
78
  return (error, req, res, next) => {
79
79
  if (res.headersSent) {
80
80
  next(error);
@@ -99,7 +99,9 @@ export function errorHandler(options = {}) {
99
99
  path: req.path,
100
100
  method: req.method,
101
101
  query: req.query,
102
- body: req.body,
102
+ ...(Buffer.isBuffer(req.body)
103
+ ? { bodyContentType: req.headers["content-type"], bodyLength: req.body.length }
104
+ : { body: req.body }),
103
105
  });
104
106
  }
105
107
  }
@@ -117,7 +119,7 @@ export function errorHandler(options = {}) {
117
119
  detail: "An unexpected error occurred",
118
120
  });
119
121
  }
120
- if (includeStack && error.stack) {
122
+ if (error.stack) {
121
123
  problemDetails.stack = error.stack.split("\n").map((line) => line.trim());
122
124
  }
123
125
  if (!problemDetails.instance) {
@@ -1 +1 @@
1
- {"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../src/error-handler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../src/error-handler.ts"],"names":[],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -50,7 +50,7 @@ var DefaultErrorFormatter = class {
50
50
  return (0, _batkit_rfc9457.createExtendedProblemDetails)({
51
51
  type: "error:validation",
52
52
  title: "Validation Error",
53
- status: 400,
53
+ status: 422,
54
54
  detail: "Request validation failed",
55
55
  validationErrors: error.issues.map((issue) => ({
56
56
  field: issue.path.join("."),
@@ -83,7 +83,7 @@ var DefaultErrorFormatter = class {
83
83
  * ```
84
84
  */
85
85
  function errorHandler(options = {}) {
86
- const { formatters = [new DefaultErrorFormatter()], includeStack = true, logErrors = true, onError } = options;
86
+ const { formatters = [new DefaultErrorFormatter()], logErrors = true, onError } = options;
87
87
  return (error, req, res, next) => {
88
88
  if (res.headersSent) {
89
89
  next(error);
@@ -101,7 +101,10 @@ function errorHandler(options = {}) {
101
101
  path: req.path,
102
102
  method: req.method,
103
103
  query: req.query,
104
- body: req.body
104
+ ...Buffer.isBuffer(req.body) ? {
105
+ bodyContentType: req.headers["content-type"],
106
+ bodyLength: req.body.length
107
+ } : { body: req.body }
105
108
  });
106
109
  let problemDetails;
107
110
  const formatter = formatters.find((f) => f.canFormat(error));
@@ -112,7 +115,7 @@ function errorHandler(options = {}) {
112
115
  status: 500,
113
116
  detail: "An unexpected error occurred"
114
117
  });
115
- if (includeStack && error.stack) problemDetails.stack = error.stack.split("\n").map((line) => line.trim());
118
+ if (error.stack) problemDetails.stack = error.stack.split("\n").map((line) => line.trim());
116
119
  if (!problemDetails.instance) problemDetails.instance = req.path;
117
120
  res.status(problemDetails.status || 500).set("Content-Type", _batkit_rfc9457.PROBLEM_DETAILS_CONTENT_TYPE).json(problemDetails);
118
121
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["LoggerFacade","PROBLEM_DETAILS_CONTENT_TYPE"],"sources":["../src/error-handler.ts","../src/log-context-middleware.ts"],"sourcesContent":["import { isAppError } from \"@batkit/errors\";\nimport { LoggerFacade } from \"@batkit/logger\";\nimport {\n type ExtendedProblemDetails,\n PROBLEM_DETAILS_CONTENT_TYPE,\n createExtendedProblemDetails,\n} from \"@batkit/rfc9457\";\nimport type { NextFunction, Request, Response } from \"express\";\n\nconst logger = LoggerFacade.getLogger(\"error-handler\");\n/**\n * Interface for custom error formatters\n */\nexport interface ErrorFormatter {\n /**\n * Check if this formatter can handle the error\n */\n canFormat(error: unknown): boolean;\n\n /**\n * Format the error as RFC 9457 Problem Details\n */\n format(error: unknown): ExtendedProblemDetails;\n}\n\n/**\n * Default error formatter that handles common error types\n */\nexport class DefaultErrorFormatter implements ErrorFormatter {\n canFormat(error: unknown): boolean {\n return (\n isAppError(error) ||\n error instanceof Error ||\n this.isAxiosError(error) ||\n this.isZodError(error)\n );\n }\n\n format(error: unknown): ExtendedProblemDetails {\n // Handle AppError (from @batkit/errors)\n if (isAppError(error)) {\n return error.toRFC9457();\n }\n\n // Handle Axios errors\n if (this.isAxiosError(error)) {\n return this.formatAxiosError(error as Record<string, unknown>);\n }\n\n // Handle Zod validation errors\n if (this.isZodError(error)) {\n return this.formatZodError(error as Record<string, unknown>);\n }\n\n // Handle generic Error\n if (error instanceof Error) {\n return createExtendedProblemDetails({\n type: \"error:internal\",\n title: \"Internal Server Error\",\n status: 500,\n detail: error.message,\n });\n }\n\n // Unknown error type\n return createExtendedProblemDetails({\n type: \"error:unknown\",\n title: \"Unknown Error\",\n status: 500,\n detail: \"An unknown error occurred\",\n });\n }\n\n private isAxiosError(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"isAxiosError\" in error &&\n error.isAxiosError === true\n );\n }\n\n private isZodError(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"issues\" in error &&\n Array.isArray((error as Record<string, unknown>).issues)\n );\n }\n\n private formatAxiosError(error: Record<string, unknown>): ExtendedProblemDetails {\n const status = ((error.response as Record<string, unknown>)?.status as number) || 502;\n return createExtendedProblemDetails({\n type: \"error:upstream\",\n title: \"Upstream Service Error\",\n status,\n detail: error.message as string,\n upstreamUrl: (error.config as Record<string, unknown>)?.url as string | undefined,\n upstreamMethod: ((error.config as Record<string, unknown>)?.method as string)?.toUpperCase(),\n upstreamStatus: (error.response as Record<string, unknown>)?.status as number | undefined,\n });\n }\n\n private formatZodError(error: Record<string, unknown>): ExtendedProblemDetails {\n const validationErrors = (error.issues as Array<Record<string, unknown>>).map((issue) => ({\n field: (issue.path as unknown[]).join(\".\"),\n message: issue.message as string,\n code: issue.code as string,\n }));\n\n return createExtendedProblemDetails({\n type: \"error:validation\",\n title: \"Validation Error\",\n status: 400,\n detail: \"Request validation failed\",\n validationErrors,\n });\n }\n}\n\n/**\n * Options for error handler middleware\n */\nexport interface ErrorHandlerOptions {\n /**\n * Custom error formatters (in order of precedence)\n */\n formatters?: ErrorFormatter[];\n\n /**\n * Whether to include stack traces in responses (default: only in non-production)\n */\n includeStack?: boolean;\n\n /**\n * Whether to log errors (default: true)\n */\n logErrors?: boolean;\n\n /**\n * Custom error logger function\n */\n onError?: (error: unknown, req: Request) => void;\n}\n\n/**\n * Express error handling middleware that converts errors to RFC 9457 format\n *\n * @param options - Configuration options\n * @returns Express error middleware function\n *\n * @example\n * ```ts\n * import { errorHandler } from '@batkit/express-middleware';\n * import { NotFoundError } from '@batkit/errors';\n * import express from 'express';\n *\n * const app = express();\n *\n * app.get('/users/:id', (req, res) => {\n * throw new NotFoundError('User', req.params.id);\n * });\n *\n * // Must be added AFTER all routes\n * app.use(errorHandler());\n * ```\n */\nexport function errorHandler(\n options: ErrorHandlerOptions = {},\n): (error: Error, req: Request, res: Response, next: NextFunction) => void {\n const {\n formatters = [new DefaultErrorFormatter()],\n includeStack = true,\n logErrors = true,\n onError,\n } = options;\n\n return (error: Error, req: Request, res: Response, next: NextFunction): void => {\n // If headers already sent, delegate to default Express error handler\n if (res.headersSent) {\n next(error);\n return;\n }\n\n // Log the error\n if (logErrors) {\n if (onError) {\n onError(error, req);\n } else {\n if (isAppError(error) && error.isOperational) {\n logger.warn(\"Operational error occurred\", {\n error: error.message,\n code: error.code,\n statusCode: error.statusCode,\n path: req.path,\n method: req.method,\n });\n } else {\n logger.error(error, {\n path: req.path,\n method: req.method,\n query: req.query,\n body: req.body,\n });\n }\n }\n }\n\n // Format the error\n let problemDetails: ExtendedProblemDetails;\n\n const formatter = formatters.find((f) => f.canFormat(error));\n if (formatter) {\n problemDetails = formatter.format(error);\n } else {\n // Fallback to generic error\n problemDetails = createExtendedProblemDetails({\n type: \"error:internal\",\n title: \"Internal Server Error\",\n status: 500,\n detail: \"An unexpected error occurred\",\n });\n }\n\n // Add stack trace if enabled\n if (includeStack && error.stack) {\n problemDetails.stack = error.stack.split(\"\\n\").map((line) => line.trim());\n }\n\n // Add instance (request path)\n if (!problemDetails.instance) {\n problemDetails.instance = req.path;\n }\n\n // Send RFC 9457 response\n res\n .status(problemDetails.status || 500)\n .set(\"Content-Type\", PROBLEM_DETAILS_CONTENT_TYPE)\n .json(problemDetails);\n };\n}\n\n/**\n * Express middleware to catch async errors\n * Wraps async route handlers to ensure errors are passed to error middleware\n *\n * @param fn - Async route handler\n * @returns Wrapped route handler\n *\n * @example\n * ```ts\n * import { asyncHandler } from '@batkit/express-middleware';\n *\n * app.get('/users/:id', asyncHandler(async (req, res) => {\n * const user = await db.users.findById(req.params.id);\n * if (!user) {\n * throw new NotFoundError('User', req.params.id);\n * }\n * res.json(user);\n * }));\n * ```\n */\nexport function asyncHandler(\n fn: (req: Request, res: Response, next: NextFunction) => Promise<unknown>,\n): (req: Request, res: Response, next: NextFunction) => void {\n return (req: Request, res: Response, next: NextFunction): void => {\n Promise.resolve(fn(req, res, next)).catch(next);\n };\n}\n","import type { LogValue } from \"@batkit/logger\";\nimport { runWithContext } from \"@batkit/logger/async-local\";\nimport type { NextFunction, Request, Response } from \"express\";\n\nexport type LogContextInitializer = (req: Request) => Record<string, LogValue>;\n\nexport interface LogContextMiddlewareOptions {\n /**\n * Build initial async-local log fields for this HTTP request.\n * @default () => ({})\n */\n initialContext?: LogContextInitializer;\n}\n\n/**\n * Runs each request inside {@link runWithContext} so later code can use\n * {@link mergeLogContext} and a {@link ContextualLoggerProvider} without\n * depending on Express (`req`) deep in the stack.\n *\n * Mount this **early** in the middleware chain. Use synchronous `next()` inside\n * the callback; avoid `async` middleware that calls `next` after an `await`\n * without keeping the rest of the work in the same async context.\n */\nexport function logContextMiddleware(\n options: LogContextMiddlewareOptions = {},\n): (req: Request, res: Response, next: NextFunction) => void {\n const initialContext = options.initialContext ?? (() => ({}));\n\n return (req: Request, _res: Response, next: NextFunction) => {\n runWithContext(initialContext(req), () => next());\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["LoggerFacade","PROBLEM_DETAILS_CONTENT_TYPE"],"sources":["../src/error-handler.ts","../src/log-context-middleware.ts"],"sourcesContent":["import { isAppError } from \"@batkit/errors\";\nimport { LoggerFacade } from \"@batkit/logger\";\nimport {\n type ExtendedProblemDetails,\n PROBLEM_DETAILS_CONTENT_TYPE,\n createExtendedProblemDetails,\n} from \"@batkit/rfc9457\";\nimport type { NextFunction, Request, Response } from \"express\";\n\nconst logger = LoggerFacade.getLogger(\"error-handler\");\n/**\n * Interface for custom error formatters\n */\nexport interface ErrorFormatter {\n /**\n * Check if this formatter can handle the error\n */\n canFormat(error: unknown): boolean;\n\n /**\n * Format the error as RFC 9457 Problem Details\n */\n format(error: unknown): ExtendedProblemDetails;\n}\n\n/**\n * Default error formatter that handles common error types\n */\nexport class DefaultErrorFormatter implements ErrorFormatter {\n canFormat(error: unknown): boolean {\n return (\n isAppError(error) ||\n error instanceof Error ||\n this.isAxiosError(error) ||\n this.isZodError(error)\n );\n }\n\n format(error: unknown): ExtendedProblemDetails {\n // Handle AppError (from @batkit/errors)\n if (isAppError(error)) {\n return error.toRFC9457();\n }\n\n // Handle Axios errors\n if (this.isAxiosError(error)) {\n return this.formatAxiosError(error as Record<string, unknown>);\n }\n\n // Handle Zod validation errors\n if (this.isZodError(error)) {\n return this.formatZodError(error as Record<string, unknown>);\n }\n\n // Handle generic Error\n if (error instanceof Error) {\n return createExtendedProblemDetails({\n type: \"error:internal\",\n title: \"Internal Server Error\",\n status: 500,\n detail: error.message,\n });\n }\n\n // Unknown error type\n return createExtendedProblemDetails({\n type: \"error:unknown\",\n title: \"Unknown Error\",\n status: 500,\n detail: \"An unknown error occurred\",\n });\n }\n\n private isAxiosError(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"isAxiosError\" in error &&\n error.isAxiosError === true\n );\n }\n\n private isZodError(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"issues\" in error &&\n Array.isArray((error as Record<string, unknown>).issues)\n );\n }\n\n private formatAxiosError(error: Record<string, unknown>): ExtendedProblemDetails {\n const status = ((error.response as Record<string, unknown>)?.status as number) || 502;\n return createExtendedProblemDetails({\n type: \"error:upstream\",\n title: \"Upstream Service Error\",\n status,\n detail: error.message as string,\n upstreamUrl: (error.config as Record<string, unknown>)?.url as string | undefined,\n upstreamMethod: ((error.config as Record<string, unknown>)?.method as string)?.toUpperCase(),\n upstreamStatus: (error.response as Record<string, unknown>)?.status as number | undefined,\n });\n }\n\n private formatZodError(error: Record<string, unknown>): ExtendedProblemDetails {\n const validationErrors = (error.issues as Array<Record<string, unknown>>).map((issue) => ({\n field: (issue.path as unknown[]).join(\".\"),\n message: issue.message as string,\n code: issue.code as string,\n }));\n\n return createExtendedProblemDetails({\n type: \"error:validation\",\n title: \"Validation Error\",\n status: 422,\n detail: \"Request validation failed\",\n validationErrors,\n });\n }\n}\n\n/**\n * Options for error handler middleware\n */\nexport interface ErrorHandlerOptions {\n /**\n * Custom error formatters (in order of precedence)\n */\n formatters?: ErrorFormatter[];\n\n /**\n * Whether to log errors (default: true)\n */\n logErrors?: boolean;\n\n /**\n * Custom error logger function\n */\n onError?: (error: unknown, req: Request) => void;\n}\n\n/**\n * Express error handling middleware that converts errors to RFC 9457 format\n *\n * @param options - Configuration options\n * @returns Express error middleware function\n *\n * @example\n * ```ts\n * import { errorHandler } from '@batkit/express-middleware';\n * import { NotFoundError } from '@batkit/errors';\n * import express from 'express';\n *\n * const app = express();\n *\n * app.get('/users/:id', (req, res) => {\n * throw new NotFoundError('User', req.params.id);\n * });\n *\n * // Must be added AFTER all routes\n * app.use(errorHandler());\n * ```\n */\nexport function errorHandler(\n options: ErrorHandlerOptions = {},\n): (error: Error, req: Request, res: Response, next: NextFunction) => void {\n const { formatters = [new DefaultErrorFormatter()], logErrors = true, onError } = options;\n\n return (error: Error, req: Request, res: Response, next: NextFunction): void => {\n // If headers already sent, delegate to default Express error handler\n if (res.headersSent) {\n next(error);\n return;\n }\n\n // Log the error\n if (logErrors) {\n if (onError) {\n onError(error, req);\n } else {\n if (isAppError(error) && error.isOperational) {\n logger.warn(\"Operational error occurred\", {\n error: error.message,\n code: error.code,\n statusCode: error.statusCode,\n path: req.path,\n method: req.method,\n });\n } else {\n logger.error(error, {\n path: req.path,\n method: req.method,\n query: req.query,\n ...(Buffer.isBuffer(req.body)\n ? { bodyContentType: req.headers[\"content-type\"], bodyLength: req.body.length }\n : { body: req.body }),\n });\n }\n }\n }\n\n // Format the error\n let problemDetails: ExtendedProblemDetails;\n\n const formatter = formatters.find((f) => f.canFormat(error));\n if (formatter) {\n problemDetails = formatter.format(error);\n } else {\n // Fallback to generic error\n problemDetails = createExtendedProblemDetails({\n type: \"error:internal\",\n title: \"Internal Server Error\",\n status: 500,\n detail: \"An unexpected error occurred\",\n });\n }\n\n // Add stack trace\n if (error.stack) {\n problemDetails.stack = error.stack.split(\"\\n\").map((line) => line.trim());\n }\n\n // Add instance (request path)\n if (!problemDetails.instance) {\n problemDetails.instance = req.path;\n }\n\n // Send RFC 9457 response\n res\n .status(problemDetails.status || 500)\n .set(\"Content-Type\", PROBLEM_DETAILS_CONTENT_TYPE)\n .json(problemDetails);\n };\n}\n\n/**\n * Express middleware to catch async errors\n * Wraps async route handlers to ensure errors are passed to error middleware\n *\n * @param fn - Async route handler\n * @returns Wrapped route handler\n *\n * @example\n * ```ts\n * import { asyncHandler } from '@batkit/express-middleware';\n *\n * app.get('/users/:id', asyncHandler(async (req, res) => {\n * const user = await db.users.findById(req.params.id);\n * if (!user) {\n * throw new NotFoundError('User', req.params.id);\n * }\n * res.json(user);\n * }));\n * ```\n */\nexport function asyncHandler(\n fn: (req: Request, res: Response, next: NextFunction) => Promise<unknown>,\n): (req: Request, res: Response, next: NextFunction) => void {\n return (req: Request, res: Response, next: NextFunction): void => {\n Promise.resolve(fn(req, res, next)).catch(next);\n };\n}\n","import type { LogValue } from \"@batkit/logger\";\nimport { runWithContext } from \"@batkit/logger/async-local\";\nimport type { NextFunction, Request, Response } from \"express\";\n\nexport type LogContextInitializer = (req: Request) => Record<string, LogValue>;\n\nexport interface LogContextMiddlewareOptions {\n /**\n * Build initial async-local log fields for this HTTP request.\n * @default () => ({})\n */\n initialContext?: LogContextInitializer;\n}\n\n/**\n * Runs each request inside {@link runWithContext} so later code can use\n * {@link mergeLogContext} and a {@link ContextualLoggerProvider} without\n * depending on Express (`req`) deep in the stack.\n *\n * Mount this **early** in the middleware chain. Use synchronous `next()` inside\n * the callback; avoid `async` middleware that calls `next` after an `await`\n * without keeping the rest of the work in the same async context.\n */\nexport function logContextMiddleware(\n options: LogContextMiddlewareOptions = {},\n): (req: Request, res: Response, next: NextFunction) => void {\n const initialContext = options.initialContext ?? (() => ({}));\n\n return (req: Request, _res: Response, next: NextFunction) => {\n runWithContext(initialContext(req), () => next());\n };\n}\n"],"mappings":"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"}
package/dist/index.d.cts CHANGED
@@ -17,7 +17,6 @@ declare class DefaultErrorFormatter implements ErrorFormatter {
17
17
  }
18
18
  interface ErrorHandlerOptions {
19
19
  formatters?: ErrorFormatter[];
20
- includeStack?: boolean;
21
20
  logErrors?: boolean;
22
21
  onError?: (error: unknown, req: Request) => void;
23
22
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/error-handler.ts","../src/log-context-middleware.ts"],"mappings":";;;;;UAaiB,cAAA;EAIf,SAAA,CAAU,KAAA;EAKV,MAAA,CAAO,KAAA,YAAiB,sBAAsB;AAAA;AAAA,cAMnC,qBAAA,YAAiC,cAAc;EAC1D,SAAA,CAAU,KAAA;EASV,MAAA,CAAO,KAAA,YAAiB,sBAAA;EAAA,QAmChB,YAAA;EAAA,QASA,UAAA;EAAA,QASA,gBAAA;EAAA,QAaA,cAAA;AAAA;AAAA,UAoBO,mBAAA;EAIf,UAAA,GAAa,cAAA;EAKb,YAAA;EAKA,SAAA;EAKA,OAAA,IAAW,KAAA,WAAgB,GAAA,EAAK,OAAO;AAAA;AAAA,iBAyBzB,YAAA,CACd,OAAA,GAAS,mBAAA,IACP,KAAA,EAAO,KAAA,EAAO,GAAA,EAAK,OAAA,EAAS,GAAA,EAAK,QAAA,EAAU,IAAA,EAAM,YAAA;AAAA,iBA6FrC,YAAA,CACd,EAAA,GAAK,GAAA,EAAK,OAAA,EAAS,GAAA,EAAK,QAAA,EAAU,IAAA,EAAM,YAAA,KAAiB,OAAA,aACvD,GAAA,EAAK,OAAA,EAAS,GAAA,EAAK,QAAA,EAAU,IAAA,EAAM,YAAA;;;KCrQ3B,qBAAA,IAAyB,GAAA,EAAK,OAAA,KAAY,MAAA,SAAe,QAAA;AAAA,UAEpD,2BAAA;EAKf,cAAA,GAAiB,qBAAqB;AAAA;AAAA,iBAYxB,oBAAA,CACd,OAAA,GAAS,2BAAA,IACP,GAAA,EAAK,OAAA,EAAS,GAAA,EAAK,QAAA,EAAU,IAAA,EAAM,YAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/error-handler.ts","../src/log-context-middleware.ts"],"mappings":";;;;;UAaiB,cAAA;EAIf,SAAA,CAAU,KAAA;EAKV,MAAA,CAAO,KAAA,YAAiB,sBAAsB;AAAA;AAAA,cAMnC,qBAAA,YAAiC,cAAc;EAC1D,SAAA,CAAU,KAAA;EASV,MAAA,CAAO,KAAA,YAAiB,sBAAA;EAAA,QAmChB,YAAA;EAAA,QASA,UAAA;EAAA,QASA,gBAAA;EAAA,QAaA,cAAA;AAAA;AAAA,UAoBO,mBAAA;EAIf,UAAA,GAAa,cAAA;EAKb,SAAA;EAKA,OAAA,IAAW,KAAA,WAAgB,GAAA,EAAK,OAAO;AAAA;AAAA,iBAyBzB,YAAA,CACd,OAAA,GAAS,mBAAA,IACP,KAAA,EAAO,KAAA,EAAO,GAAA,EAAK,OAAA,EAAS,GAAA,EAAK,QAAA,EAAU,IAAA,EAAM,YAAA;AAAA,iBA0FrC,YAAA,CACd,EAAA,GAAK,GAAA,EAAK,OAAA,EAAS,GAAA,EAAK,QAAA,EAAU,IAAA,EAAM,YAAA,KAAiB,OAAA,aACvD,GAAA,EAAK,OAAA,EAAS,GAAA,EAAK,QAAA,EAAU,IAAA,EAAM,YAAA;;;KC7P3B,qBAAA,IAAyB,GAAA,EAAK,OAAA,KAAY,MAAA,SAAe,QAAA;AAAA,UAEpD,2BAAA;EAKf,cAAA,GAAiB,qBAAqB;AAAA;AAAA,iBAYxB,oBAAA,CACd,OAAA,GAAS,2BAAA,IACP,GAAA,EAAK,OAAA,EAAS,GAAA,EAAK,QAAA,EAAU,IAAA,EAAM,YAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@batkit/express-middleware",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Express middleware for error handling and request context (Node.js only)",
5
5
  "keywords": [
6
6
  "error-handling",
@@ -46,7 +46,7 @@
46
46
  "access": "public"
47
47
  },
48
48
  "dependencies": {
49
- "@batkit/errors": "0.1.1",
49
+ "@batkit/errors": "0.1.2",
50
50
  "@batkit/logger": "0.1.1",
51
51
  "@batkit/rfc9457": "0.1.1"
52
52
  },